1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qwindowsfontdatabase.h"
43 #include "qwindowsfontdatabase_ft.h" // for default font
44 #include "qwindowscontext.h"
45 #include "qwindowsfontengine.h"
46 #include "qwindowsfontenginedirectwrite.h"
47 #include "qtwindows_additional.h"
49 #include <QtGui/QFont>
50 #include <QtGui/QGuiApplication>
52 #include <QtCore/qmath.h>
53 #include <QtCore/QDebug>
54 #include <QtCore/QtEndian>
59 # include "qplatformfunctions_wince.h"
62 #if !defined(QT_NO_DIRECTWRITE)
69 // Helper classes for creating font engines directly from font data
74 // Common structure for all formats of the "name" table
97 quint16 entrySelector;
101 struct TableDirectory
116 qint16 subscriptXSize;
117 qint16 subscriptYSize;
118 qint16 subscriptXOffset;
119 qint16 subscriptYOffset;
120 qint16 superscriptXSize;
121 qint16 superscriptYSize;
122 qint16 superscriptXOffset;
123 qint16 superscriptYOffset;
124 qint16 strikeOutSize;
125 qint16 strikeOutPosition;
128 quint32 unicodeRanges[4];
131 quint16 firstCharIndex;
132 quint16 lastCharIndex;
134 qint16 typoDescender;
138 quint32 codepageRanges[2];
151 EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {}
153 QString changeFamilyName(const QString &newFamilyName);
154 QByteArray data() const { return m_fontData; }
155 TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
156 QString familyName(TableDirectory *nameTableDirectory = 0);
159 QByteArray m_fontData;
162 TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
164 Q_ASSERT(tagName.size() == 4);
165 quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData()));
167 OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
168 TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
170 TableDirectory *nameTableDirectoryEntry = 0;
171 for (int i = 0; i < qFromBigEndian<quint16>(offsetSubTable->numTables); ++i, ++tableDirectory) {
172 if (tableDirectory->identifier == tagId) {
173 nameTableDirectoryEntry = tableDirectory;
178 return nameTableDirectoryEntry;
181 QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
185 if (nameTableDirectoryEntry == 0)
186 nameTableDirectoryEntry = tableDirectoryEntry("name");
188 if (nameTableDirectoryEntry != 0) {
189 NameTable *nameTable = reinterpret_cast<NameTable *>(
190 m_fontData.data() + qFromBigEndian<quint32>(nameTableDirectoryEntry->offset));
191 NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
192 for (int i = 0; i < qFromBigEndian<quint16>(nameTable->count); ++i, ++nameRecord) {
193 if (qFromBigEndian<quint16>(nameRecord->nameID) == 1
194 && qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows
195 && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English
196 const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
197 + qFromBigEndian<quint16>(nameTable->stringOffset)
198 + qFromBigEndian<quint16>(nameRecord->offset);
200 const quint16 *s = reinterpret_cast<const quint16 *>(ptr);
201 const quint16 *e = s + qFromBigEndian<quint16>(nameRecord->length) / sizeof(quint16);
203 name += QChar( qFromBigEndian<quint16>(*s++));
212 QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
214 TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
215 if (nameTableDirectoryEntry == 0)
218 QString oldFamilyName = familyName(nameTableDirectoryEntry);
220 // Reserve size for name table header, five required name records and string
221 const int requiredRecordCount = 5;
222 quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
224 int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
225 int newFamilyNameSize = newFamilyName.size() * sizeof(quint16);
227 const QString regularString = QString::fromLatin1("Regular");
228 int regularStringSize = regularString.size() * sizeof(quint16);
230 // Align table size of table to 32 bits (pad with 0)
231 int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
233 QByteArray newNameTable(fullSize, char(0));
236 NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
237 nameTable->count = qbswap<quint16>(requiredRecordCount);
238 nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
240 NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
241 for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
242 nameRecord->nameID = qbswap<quint16>(nameIds[i]);
243 nameRecord->encodingID = qbswap<quint16>(1);
244 nameRecord->languageID = qbswap<quint16>(0x0409);
245 nameRecord->platformID = qbswap<quint16>(3);
246 nameRecord->length = qbswap<quint16>(newFamilyNameSize);
248 // Special case for sub-family
249 if (nameIds[i] == 4) {
250 nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
251 nameRecord->length = qbswap<quint16>(regularStringSize);
255 // nameRecord now points to string data
256 quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
257 const quint16 *sourceString = newFamilyName.utf16();
258 for (int i = 0; i < newFamilyName.size(); ++i)
259 stringStorage[i] = qbswap<quint16>(sourceString[i]);
260 stringStorage += newFamilyName.size();
262 sourceString = regularString.utf16();
263 for (int i = 0; i < regularString.size(); ++i)
264 stringStorage[i] = qbswap<quint16>(sourceString[i]);
267 quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
268 quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
270 quint32 checkSum = 0;
272 checkSum += qFromBigEndian<quint32>(*(p++));
274 nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
275 nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
276 nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
278 m_fontData.append(newNameTable);
280 return oldFamilyName;
283 #if !defined(QT_NO_DIRECTWRITE)
285 class DirectWriteFontFileStream: public IDWriteFontFileStream
288 DirectWriteFontFileStream(const QByteArray &fontData)
289 : m_fontData(fontData)
290 , m_referenceCount(0)
294 ~DirectWriteFontFileStream()
298 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
299 ULONG STDMETHODCALLTYPE AddRef();
300 ULONG STDMETHODCALLTYPE Release();
302 HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
303 UINT64 fragmentSize, OUT void **fragmentContext);
304 void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext);
305 HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize);
306 HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime);
309 QByteArray m_fontData;
310 ULONG m_referenceCount;
313 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
315 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
321 return E_NOINTERFACE;
325 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
327 return InterlockedIncrement(&m_referenceCount);
330 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
332 ULONG newCount = InterlockedDecrement(&m_referenceCount);
338 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
339 const void **fragmentStart,
342 OUT void **fragmentContext)
344 *fragmentContext = NULL;
345 if (fragmentSize + fileOffset <= m_fontData.size()) {
346 *fragmentStart = m_fontData.data() + fileOffset;
349 *fragmentStart = NULL;
354 void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
358 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
360 *fileSize = m_fontData.size();
364 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
370 class DirectWriteFontFileLoader: public IDWriteFontFileLoader
373 DirectWriteFontFileLoader() : m_referenceCount(0) {}
375 ~DirectWriteFontFileLoader()
379 inline void addKey(const void *key, const QByteArray &fontData)
381 Q_ASSERT(!m_fontDatas.contains(key));
382 m_fontDatas.insert(key, fontData);
385 inline void removeKey(const void *key)
387 m_fontDatas.remove(key);
390 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
391 ULONG STDMETHODCALLTYPE AddRef();
392 ULONG STDMETHODCALLTYPE Release();
394 HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
395 UINT32 fontFileReferenceKeySize,
396 OUT IDWriteFontFileStream **fontFileStream);
399 ULONG m_referenceCount;
400 QHash<const void *, QByteArray> m_fontDatas;
403 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
406 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
412 return E_NOINTERFACE;
416 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
418 return InterlockedIncrement(&m_referenceCount);
421 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
423 ULONG newCount = InterlockedDecrement(&m_referenceCount);
429 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
430 void const *fontFileReferenceKey,
431 UINT32 fontFileReferenceKeySize,
432 IDWriteFontFileStream **fontFileStream)
434 Q_UNUSED(fontFileReferenceKeySize);
436 if (fontFileReferenceKeySize != sizeof(const void *)) {
437 qWarning("%s: Wrong key size", __FUNCTION__);
441 const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
442 *fontFileStream = NULL;
443 if (!m_fontDatas.contains(key))
446 QByteArray fontData = m_fontDatas.value(key);
447 DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
449 *fontFileStream = stream;
454 class CustomFontFileLoader
457 CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0)
459 HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
460 __uuidof(IDWriteFactory),
461 reinterpret_cast<IUnknown **>(&m_directWriteFactory));
463 qErrnoWarning(hres, "%s: DWriteCreateFactory failed.", __FUNCTION__);
465 m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
466 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
470 ~CustomFontFileLoader()
472 if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
473 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
475 if (m_directWriteFactory != 0)
476 m_directWriteFactory->Release();
479 void addKey(const void *key, const QByteArray &fontData)
481 if (m_directWriteFontFileLoader != 0)
482 m_directWriteFontFileLoader->addKey(key, fontData);
485 void removeKey(const void *key)
487 if (m_directWriteFontFileLoader != 0)
488 m_directWriteFontFileLoader->removeKey(key);
491 IDWriteFontFileLoader *loader() const
493 return m_directWriteFontFileLoader;
497 IDWriteFactory *m_directWriteFactory;
498 DirectWriteFontFileLoader *m_directWriteFontFileLoader;
503 } // Anonymous namespace
506 \struct QWindowsFontEngineData
507 \brief Static constant data shared by the font engines.
508 \ingroup qt-lighthouse-win
511 QWindowsFontEngineData::QWindowsFontEngineData()
512 : clearTypeEnabled(false)
513 , fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma())
514 #if !defined(QT_NO_DIRECTWRITE)
515 , directWriteFactory(0)
516 , directWriteGdiInterop(0)
519 // from qapplication_win.cpp
521 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0))
522 clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE);
524 const qreal gray_gamma = 2.31;
525 for (int i=0; i<256; ++i)
526 pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
528 HDC displayDC = GetDC(0);
529 hdc = CreateCompatibleDC(displayDC);
530 ReleaseDC(0, displayDC);
533 QWindowsFontEngineData::~QWindowsFontEngineData()
537 #if !defined(QT_NO_DIRECTWRITE)
538 if (directWriteGdiInterop)
539 directWriteGdiInterop->Release();
540 if (directWriteFactory)
541 directWriteFactory->Release();
545 qreal QWindowsFontDatabase::fontSmoothingGamma()
549 if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0))
550 result = qreal(winSmooth) / qreal(1000.0);
552 // Safeguard ourselves against corrupt registry values...
553 if (result > 5 || result < 1)
558 #if !defined(QT_NO_DIRECTWRITE)
559 static inline bool initDirectWrite(QWindowsFontEngineData *d)
561 if (!d->directWriteFactory) {
562 const HRESULT hr = DWriteCreateFactory(
563 DWRITE_FACTORY_TYPE_SHARED,
564 __uuidof(IDWriteFactory),
565 reinterpret_cast<IUnknown **>(&d->directWriteFactory)
568 qErrnoWarning("%s: DWriteCreateFactory failed", __FUNCTION__);
572 if (!d->directWriteGdiInterop) {
573 const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
575 qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__);
582 #endif // !defined(QT_NO_DIRECTWRITE)
585 \class QWindowsFontDatabase
586 \brief Font database for Windows
588 \note The Qt 4.8 WIndows font database employed a mechanism of
589 delayed population of the database again passing a font name
590 to EnumFontFamiliesEx(), working around the fact that
591 EnumFontFamiliesEx() does not list all fonts by default.
592 This should be introduced to Lighthouse as well?
594 \ingroup qt-lighthouse-win
597 QDebug operator<<(QDebug d, const QFontDef &def)
599 d.nospace() << "Family=" << def.family << " Stylename=" << def.styleName
600 << " pointsize=" << def.pointSize << " pixelsize=" << def.pixelSize
601 << " styleHint=" << def.styleHint << " weight=" << def.weight
602 << " stretch=" << def.stretch << " hintingPreference="
603 << def.hintingPreference << ' ';
607 /* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits().
608 * Fixme: Make public? */
610 // see the Unicode subset bitfields in the MSDN docs
611 static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
662 // SimplifiedChinese,
664 // TraditionalChinese,
671 { 0, 127 }, // same as latin1
684 SimplifiedChineseCsbBit = 18,
685 TraditionalChineseCsbBit = 20,
690 static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4],
691 quint32 codePageRange[2],
692 QSupportedWritingSystems *ws)
694 bool hasScript = false;
695 for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
696 int bit = requiredUnicodeBits[i][0];
698 int flag = 1 << (bit&31);
699 if (bit != 126 && unicodeRange[index] & flag) {
700 bit = requiredUnicodeBits[i][1];
703 flag = 1 << (bit&31);
704 if (bit == 127 || unicodeRange[index] & flag) {
705 ws->setSupported(QFontDatabase::WritingSystem(i), true);
710 if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
711 ws->setSupported(QFontDatabase::SimplifiedChinese, true);
714 if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
715 ws->setSupported(QFontDatabase::TraditionalChinese, true);
718 if(codePageRange[0] & (1 << JapaneseCsbBit)) {
719 ws->setSupported(QFontDatabase::Japanese, true);
721 //qDebug("font %s supports Japanese", familyName.latin1());
723 if(codePageRange[0] & (1 << KoreanCsbBit)) {
724 ws->setSupported(QFontDatabase::Korean, true);
728 ws->setSupported(QFontDatabase::Symbol, true);
731 // convert 0 ~ 1000 integer to QFont::Weight
732 static inline QFont::Weight weightFromInteger(long weight)
737 return QFont::Normal;
739 return QFont::DemiBold;
745 static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName)
747 if (scriptName == QStringLiteral("Western")
748 || scriptName == QStringLiteral("Baltic")
749 || scriptName == QStringLiteral("Central European")
750 || scriptName == QStringLiteral("Turkish")
751 || scriptName == QStringLiteral("Vietnamese")
752 || scriptName == QStringLiteral("OEM/Dos"))
753 return QFontDatabase::Latin;
754 if (scriptName == QStringLiteral("Thai"))
755 return QFontDatabase::Thai;
756 if (scriptName == QStringLiteral("Symbol")
757 || scriptName == QStringLiteral("Other"))
758 return QFontDatabase::Symbol;
759 if (scriptName == QStringLiteral("CHINESE_GB2312"))
760 return QFontDatabase::SimplifiedChinese;
761 if (scriptName == QStringLiteral("CHINESE_BIG5"))
762 return QFontDatabase::TraditionalChinese;
763 if (scriptName == QStringLiteral("Cyrillic"))
764 return QFontDatabase::Cyrillic;
765 if (scriptName == QStringLiteral("Hangul"))
766 return QFontDatabase::Korean;
767 if (scriptName == QStringLiteral("Hebrew"))
768 return QFontDatabase::Hebrew;
769 if (scriptName == QStringLiteral("Greek"))
770 return QFontDatabase::Greek;
771 if (scriptName == QStringLiteral("Japanese"))
772 return QFontDatabase::Japanese;
773 if (scriptName == QStringLiteral("Arabic"))
774 return QFontDatabase::Arabic;
775 return QFontDatabase::Any;
781 // GetFontData expects the tags in little endian ;(
782 #define MAKE_TAG(ch1, ch2, ch3, ch4) (\
783 (((quint32)(ch4)) << 24) | \
784 (((quint32)(ch3)) << 16) | \
785 (((quint32)(ch2)) << 8) | \
789 bool localizedName(const QString &name)
791 const QChar *c = name.unicode();
792 for (int i = 0; i < name.length(); ++i) {
793 if (c[i].unicode() >= 0x100)
799 static inline quint16 getUShort(const unsigned char *p)
808 static QString getEnglishName(const uchar *table, quint32 bytes)
814 MS_LangIdEnglish = 0x009
817 // get the name table
819 quint16 string_offset;
820 const unsigned char *names;
822 int microsoft_id = -1;
826 if (getUShort(table) != 0)
829 count = getUShort(table+2);
830 string_offset = getUShort(table+4);
833 if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
836 for (int i = 0; i < count; ++i) {
837 // search for the correct name entry
839 quint16 platform_id = getUShort(names + i*NameRecordSize);
840 quint16 encoding_id = getUShort(names + 2 + i*NameRecordSize);
841 quint16 language_id = getUShort(names + 4 + i*NameRecordSize);
842 quint16 name_id = getUShort(names + 6 + i*NameRecordSize);
844 if (name_id != FamilyId)
848 PlatformId_Unicode = 0,
849 PlatformId_Apple = 1,
850 PlatformId_Microsoft = 3
853 quint16 length = getUShort(names + 8 + i*NameRecordSize);
854 quint16 offset = getUShort(names + 10 + i*NameRecordSize);
855 if (DWORD(string_offset + offset + length) >= bytes)
858 if ((platform_id == PlatformId_Microsoft
859 && (encoding_id == 0 || encoding_id == 1))
860 && (language_id & 0x3ff) == MS_LangIdEnglish
861 && microsoft_id == -1)
863 // not sure if encoding id 4 for Unicode is utf16 or ucs4...
864 else if (platform_id == PlatformId_Unicode && encoding_id < 4 && unicode_id == -1)
866 else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0)
870 bool unicode = false;
872 if (microsoft_id != -1) {
875 } else if (apple_id != -1) {
878 } else if (unicode_id != -1) {
883 quint16 length = getUShort(names + 8 + id*NameRecordSize);
884 quint16 offset = getUShort(names + 10 + id*NameRecordSize);
889 i18n_name.resize(length);
890 QChar *uc = (QChar *) i18n_name.unicode();
891 const unsigned char *string = table + string_offset + offset;
892 for (int i = 0; i < length; ++i)
893 uc[i] = getUShort(string + 2*i);
897 i18n_name.resize(length);
898 QChar *uc = (QChar *) i18n_name.unicode();
899 const unsigned char *string = table + string_offset + offset;
900 for (int i = 0; i < length; ++i)
901 uc[i] = QLatin1Char(string[i]);
906 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
910 QString getEnglishName(const QString &familyName)
914 HDC hdc = GetDC( 0 );
916 memset(&lf, 0, sizeof(LOGFONT));
917 memcpy(lf.lfFaceName, familyName.utf16(), qMin(LF_FACESIZE, familyName.length()) * sizeof(wchar_t));
918 lf.lfCharSet = DEFAULT_CHARSET;
919 HFONT hfont = CreateFontIndirect(&lf);
926 HGDIOBJ oldobj = SelectObject( hdc, hfont );
928 const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
930 // get the name table
931 unsigned char *table = 0;
933 DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
934 if ( bytes == GDI_ERROR ) {
935 // ### Unused variable
936 // int err = GetLastError();
940 table = new unsigned char[bytes];
941 GetFontData(hdc, name_tag, 0, table, bytes);
942 if ( bytes == GDI_ERROR )
945 i18n_name = getEnglishName(table, bytes);
948 SelectObject( hdc, oldobj );
949 DeleteObject( hfont );
952 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
956 Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
958 static bool addFontToDatabase(QString familyName, const QString &scriptName,
959 const TEXTMETRIC *textmetric,
960 const FONTSIGNATURE *signature,
963 // the "@family" fonts are just the same as "family". Ignore them.
964 if (familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QStringLiteral("WST_")))
967 static const int SMOOTH_SCALABLE = 0xffff;
968 const QString foundryName; // No such concept.
969 const NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
970 const bool fixed = !(tm->tmPitchAndFamily & TMPF_FIXED_PITCH);
971 const bool ttf = (tm->tmPitchAndFamily & TMPF_TRUETYPE);
972 const bool scalable = tm->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
973 const int size = scalable ? SMOOTH_SCALABLE : tm->tmHeight;
974 const QFont::Style style = tm->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
975 const bool antialias = false;
976 const QFont::Weight weight = weightFromInteger(tm->tmWeight);
977 const QFont::Stretch stretch = QFont::Unstretched;
979 #ifndef QT_NO_DEBUG_OUTPUT
980 if (QWindowsContext::verboseFonts > 2) {
981 QDebug nospace = qDebug().nospace();
982 nospace << __FUNCTION__ << familyName << scriptName
984 if (type & DEVICE_FONTTYPE)
985 nospace << " DEVICE";
986 if (type & RASTER_FONTTYPE)
987 nospace << " RASTER";
988 if (type & TRUETYPE_FONTTYPE)
989 nospace << " TRUETYPE";
990 nospace << " scalable=" << scalable << " Size=" << size
991 << " Style=" << style << " Weight=" << weight
992 << " stretch=" << stretch;
997 if (ttf && localizedName(familyName))
998 englishName = getEnglishName(familyName);
1000 QSupportedWritingSystems writingSystems;
1001 if (type & TRUETYPE_FONTTYPE) {
1002 quint32 unicodeRange[4] = {
1003 signature->fsUsb[0], signature->fsUsb[1],
1004 signature->fsUsb[2], signature->fsUsb[3]
1006 quint32 codePageRange[2] = {
1007 signature->fsCsb[0], signature->fsCsb[1]
1010 if (signature->fsUsb[0] == 0) {
1011 // If the unicode ranges bit mask is zero then
1012 // EnumFontFamiliesEx failed to determine it properly.
1013 // In this case we just pretend that the font supports all languages.
1014 unicodeRange[0] = 0xbfffffff; // second most significant bit must be zero
1015 unicodeRange[1] = 0xffffffff;
1016 unicodeRange[2] = 0xffffffff;
1017 unicodeRange[3] = 0xffffffff;
1020 writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems);
1021 // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
1022 // the symbol for Baht, and Windows thus reports that it supports the Thai script.
1023 // Since it's the default UI font on this platform, most widgets will be unable to
1024 // display Thai text by default. As a temporary work around, we special case Segoe UI
1025 // and remove the Thai script from its list of supported writing systems.
1026 if (writingSystems.supported(QFontDatabase::Thai) &&
1027 familyName == QStringLiteral("Segoe UI"))
1028 writingSystems.setSupported(QFontDatabase::Thai, false);
1030 const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName);
1031 if (ws != QFontDatabase::Any)
1032 writingSystems.setSupported(ws);
1035 QPlatformFontDatabase::registerFont(familyName, foundryName, weight,
1036 style, stretch, antialias, scalable, size, fixed, writingSystems, 0);
1037 // add fonts windows can generate for us:
1038 if (weight <= QFont::DemiBold)
1039 QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold,
1040 style, stretch, antialias, scalable, size, fixed, writingSystems, 0);
1041 if (style != QFont::StyleItalic)
1042 QPlatformFontDatabase::registerFont(familyName, foundryName, weight,
1043 QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0);
1044 if (weight <= QFont::DemiBold && style != QFont::StyleItalic)
1045 QPlatformFontDatabase::registerFont(familyName, foundryName, QFont::Bold,
1046 QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, 0);
1048 if (!englishName.isEmpty())
1049 qt_registerAliasToFontFamily(familyName, englishName);
1054 static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
1055 int type, LPARAM namesSetIn)
1057 typedef QSet<QString> StringSet;
1058 const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
1059 const QString script = QString::fromWCharArray(f->elfScript);
1061 const FONTSIGNATURE signature = textmetric->ntmFontSig;
1063 // NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
1064 // identical to a TEXTMETRIC except for the last four members, which we don't use
1066 if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type))
1067 reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName);
1069 // keep on enumerating
1073 void QWindowsFontDatabase::populateFontDatabase()
1076 removeApplicationFonts();
1077 QPlatformFontDatabase::populateFontDatabase();
1078 populate(); // Called multiple times.
1079 // Work around EnumFontFamiliesEx() not listing the system font, see below.
1080 const QString sysFontFamily = QGuiApplication::font().family();
1081 if (!m_families.contains(sysFontFamily))
1082 populate(sysFontFamily);
1086 \brief Populate font database using EnumFontFamiliesEx().
1088 Normally, leaving the name empty should enumerate
1089 all fonts, however, system fonts like "MS Shell Dlg 2"
1090 are only found when specifying the name explicitly.
1093 void QWindowsFontDatabase::populate(const QString &family)
1096 if (QWindowsContext::verboseFonts)
1097 qDebug() << __FUNCTION__ << m_families.size() << family;
1099 HDC dummy = GetDC(0);
1101 lf.lfCharSet = DEFAULT_CHARSET;
1102 if (family.size() >= LF_FACESIZE) {
1103 qWarning("%s: Unable to enumerate family '%s'.",
1104 __FUNCTION__, qPrintable(family));
1107 wmemcpy(lf.lfFaceName, reinterpret_cast<const wchar_t*>(family.utf16()),
1109 lf.lfPitchAndFamily = 0;
1110 EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont,
1111 (LPARAM)&m_families, 0);
1112 ReleaseDC(0, dummy);
1115 QWindowsFontDatabase::QWindowsFontDatabase() :
1116 m_fontEngineData(new QWindowsFontEngineData)
1118 // Properties accessed by QWin32PrintEngine (QtPrintSupport)
1119 static const int hfontMetaTypeId = qRegisterMetaType<HFONT>();
1120 static const int logFontMetaTypeId = qRegisterMetaType<LOGFONT>();
1121 Q_UNUSED(hfontMetaTypeId)
1122 Q_UNUSED(logFontMetaTypeId)
1124 if (QWindowsContext::verboseFonts)
1125 qDebug() << __FUNCTION__ << "Clear type: "
1126 << m_fontEngineData->clearTypeEnabled << "gamma: "
1127 << m_fontEngineData->fontSmoothingGamma;
1130 QWindowsFontDatabase::~QWindowsFontDatabase()
1132 removeApplicationFonts();
1135 QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef,
1136 QUnicodeTables::Script script,
1139 QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef,
1140 0, QWindowsContext::instance()->defaultDPI(), false,
1141 QStringList(), m_fontEngineData);
1142 if (QWindowsContext::verboseFonts)
1143 qDebug() << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle;
1147 QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
1149 EmbeddedFont font(fontData);
1150 QFontEngine *fontEngine = 0;
1152 #if !defined(QT_NO_DIRECTWRITE)
1153 if (hintingPreference == QFont::PreferDefaultHinting
1154 || hintingPreference == QFont::PreferFullHinting)
1158 CoCreateGuid(&guid);
1160 QString uniqueFamilyName = QLatin1Char('f')
1161 + QString::number(guid.Data1, 36) + QLatin1Char('-')
1162 + QString::number(guid.Data2, 36) + QLatin1Char('-')
1163 + QString::number(guid.Data3, 36) + QLatin1Char('-')
1164 + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
1166 QString actualFontName = font.changeFamilyName(uniqueFamilyName);
1167 if (actualFontName.isEmpty()) {
1168 qWarning("%s: Can't change family name of font", __FUNCTION__);
1173 QByteArray newFontData = font.data();
1174 HANDLE fontHandle = AddFontMemResourceEx((void *)newFontData.constData(), newFontData.size(), 0,
1176 if (count == 0 && fontHandle != 0) {
1177 RemoveFontMemResourceEx(fontHandle);
1181 if (fontHandle == 0) {
1182 qWarning("%s: AddFontMemResourceEx failed", __FUNCTION__);
1185 request.family = uniqueFamilyName;
1186 request.pixelSize = pixelSize;
1187 request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch;
1188 request.hintingPreference = hintingPreference;
1190 fontEngine = QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
1191 QWindowsContext::instance()->defaultDPI(), false, QStringList(),
1195 if (request.family != fontEngine->fontDef.family) {
1196 qWarning("%s: Failed to load font. Got fallback instead: %s",
1197 __FUNCTION__, qPrintable(fontEngine->fontDef.family));
1198 if (fontEngine->cache_count == 0 && fontEngine->ref.load() == 0)
1202 Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref.load() == 0);
1204 // Override the generated font name
1205 static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1206 fontEngine->fontDef.family = actualFontName;
1207 UniqueFontData uniqueData;
1208 uniqueData.handle = fontHandle;
1209 uniqueData.refCount.ref();
1210 m_uniqueFontData[uniqueFamilyName] = uniqueData;
1213 RemoveFontMemResourceEx(fontHandle);
1217 #if !defined(QT_NO_DIRECTWRITE)
1219 CustomFontFileLoader fontFileLoader;
1220 fontFileLoader.addKey(this, fontData);
1222 IDWriteFactory *factory = 0;
1223 HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
1224 __uuidof(IDWriteFactory),
1225 reinterpret_cast<IUnknown **>(&factory));
1227 qErrnoWarning(hres, "%s: DWriteCreateFactory failed", __FUNCTION__);
1231 IDWriteFontFile *fontFile = 0;
1234 hres = factory->CreateCustomFontFileReference(&key, sizeof(void *),
1235 fontFileLoader.loader(), &fontFile);
1237 qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
1242 BOOL isSupportedFontType;
1243 DWRITE_FONT_FILE_TYPE fontFileType;
1244 DWRITE_FONT_FACE_TYPE fontFaceType;
1245 UINT32 numberOfFaces;
1246 fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
1247 if (!isSupportedFontType) {
1248 fontFile->Release();
1253 IDWriteFontFace *directWriteFontFace = 0;
1254 hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE,
1255 &directWriteFontFace);
1257 qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
1258 fontFile->Release();
1263 fontFile->Release();
1265 fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, pixelSize,
1268 // Get font family from font data
1269 fontEngine->fontDef.family = font.familyName();
1271 directWriteFontFace->Release();
1276 // Get style and weight info
1277 if (fontEngine != 0) {
1278 TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
1279 if (os2TableEntry != 0) {
1280 const OS2Table *os2Table =
1281 reinterpret_cast<const OS2Table *>(fontData.constData()
1282 + qFromBigEndian<quint32>(os2TableEntry->offset));
1284 bool italic = qFromBigEndian<quint16>(os2Table->selection) & 1;
1285 bool oblique = qFromBigEndian<quint16>(os2Table->selection) & 128;
1288 fontEngine->fontDef.style = QFont::StyleItalic;
1290 fontEngine->fontDef.style = QFont::StyleOblique;
1292 fontEngine->fontDef.style = QFont::StyleNormal;
1294 fontEngine->fontDef.weight = weightFromInteger(qFromBigEndian<quint16>(os2Table->weightClass));
1298 if (QWindowsContext::verboseFonts)
1299 qDebug() << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
1303 QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
1305 QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script);
1306 if (!result.isEmpty())
1309 switch (styleHint) {
1311 result << QString::fromLatin1("Times New Roman");
1313 case QFont::Courier:
1314 result << QString::fromLatin1("Courier New");
1316 case QFont::Monospace:
1317 result << QString::fromLatin1("Courier New");
1319 case QFont::Cursive:
1320 result << QString::fromLatin1("Comic Sans MS");
1322 case QFont::Fantasy:
1323 result << QString::fromLatin1("Impact");
1325 case QFont::Decorative:
1326 result << QString::fromLatin1("Old English");
1328 case QFont::Helvetica:
1331 result << QString::fromLatin1("Arial");
1334 if (QWindowsContext::verboseFonts)
1335 qDebug() << __FUNCTION__ << family << style << styleHint
1336 << script << result << m_families.size();
1340 static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
1342 QList<quint32> offsets;
1343 const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
1344 if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
1345 if (headerTag != MAKE_TAG(0, 1, 0, 0)
1346 && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
1347 && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
1348 && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
1353 const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
1354 for (uint i = 0; i < numFonts; ++i) {
1355 offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
1360 static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
1362 const quint16 numTables = qFromBigEndian<quint16>(data + 4);
1363 for (uint i = 0; i < numTables; ++i) {
1364 const quint32 offset = 12 + 16 * i;
1365 if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
1366 *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
1367 *length = qFromBigEndian<quint32>(data + offset + 12);
1376 static void getFamiliesAndSignatures(const QByteArray &fontData,
1377 QStringList *families,
1378 QVector<FONTSIGNATURE> *signatures)
1380 const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
1382 QList<quint32> offsets = getTrueTypeFontOffsets(data);
1383 if (offsets.isEmpty())
1386 for (int i = 0; i < offsets.count(); ++i) {
1387 const uchar *font = data + offsets.at(i);
1390 getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
1393 QString name = getEnglishName(table, length);
1397 families->append(name);
1400 FONTSIGNATURE signature;
1401 getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
1402 if (table && length >= 86) {
1403 // Offsets taken from OS/2 table in the TrueType spec
1404 signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
1405 signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
1406 signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
1407 signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
1409 signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
1410 signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
1412 memset(&signature, 0, sizeof(signature));
1414 signatures->append(signature);
1419 QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
1421 WinApplicationFont font;
1422 font.fileName = fileName;
1423 QVector<FONTSIGNATURE> signatures;
1424 QStringList families;
1426 if (!fontData.isEmpty()) {
1427 getFamiliesAndSignatures(fontData, &families, &signatures);
1428 if (families.isEmpty())
1432 font.handle = AddFontMemResourceEx((void *)fontData.constData(), fontData.size(), 0,
1434 if (font.handle == 0)
1435 return QStringList();
1437 // Memory fonts won't show up in enumeration, so do add them the hard way.
1438 for (int j = 0; j < families.count(); ++j) {
1439 const QString familyName = families.at(j);
1442 memset(&lf, 0, sizeof(LOGFONT));
1443 memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE, familyName.size()));
1444 lf.lfCharSet = DEFAULT_CHARSET;
1445 HFONT hfont = CreateFontIndirect(&lf);
1446 HGDIOBJ oldobj = SelectObject(hdc, hfont);
1448 TEXTMETRIC textMetrics;
1449 GetTextMetrics(hdc, &textMetrics);
1451 addFontToDatabase(familyName, QString(), &textMetrics, &signatures.at(j),
1454 SelectObject(hdc, oldobj);
1455 DeleteObject(hfont);
1460 if (!f.open(QIODevice::ReadOnly))
1462 QByteArray data = f.readAll();
1465 getFamiliesAndSignatures(data, &families, 0);
1466 if (families.isEmpty())
1469 if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0)
1470 return QStringList();
1474 // Fonts based on files are added via populate, as they will show up in font enumeration.
1475 for (int j = 0; j < families.count(); ++j)
1476 populate(families.at(j));
1479 m_applicationFonts << font;
1484 void QWindowsFontDatabase::removeApplicationFonts()
1486 foreach (const WinApplicationFont &font, m_applicationFonts) {
1488 RemoveFontMemResourceEx(font.handle);
1490 RemoveFontResourceExW((LPCWSTR)font.fileName.utf16(), FR_PRIVATE, 0);
1493 m_applicationFonts.clear();
1496 void QWindowsFontDatabase::releaseHandle(void *handle)
1498 if (handle && QWindowsContext::verboseFonts)
1499 qDebug() << __FUNCTION__ << handle;
1502 QString QWindowsFontDatabase::fontDir() const
1504 const QString result = QPlatformFontDatabase::fontDir();
1505 if (QWindowsContext::verboseFonts)
1506 qDebug() << __FUNCTION__ << result;
1510 bool QWindowsFontDatabase::fontsAlwaysScalable() const
1515 void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont)
1517 if (m_uniqueFontData.contains(uniqueFont)) {
1518 if (!m_uniqueFontData[uniqueFont].refCount.deref()) {
1519 RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle);
1520 m_uniqueFontData.remove(uniqueFont);
1525 void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
1527 if (m_uniqueFontData.contains(uniqueFont))
1528 m_uniqueFontData[uniqueFont].refCount.ref();
1531 HFONT QWindowsFontDatabase::systemFont()
1533 static const HFONT stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
1534 return stock_sysfont;
1537 // Creation functions
1539 static inline bool scriptRequiresOpenType(int script)
1541 return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
1542 || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
1545 static const char *other_tryFonts[] = {
1555 static const char *jp_tryFonts [] = {
1565 static const char *ch_CN_tryFonts [] = {
1575 static const char *ch_TW_tryFonts [] = {
1585 static const char *kr_tryFonts[] = {
1595 static const char **tryFonts = 0;
1597 QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &request,
1598 HDC fontHdc, int dpi, bool rawMode,
1599 const QStringList &family_list,
1600 const QSharedPointer<QWindowsFontEngineData> &data)
1603 memset(&lf, 0, sizeof(LOGFONT));
1605 const bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc;
1607 const HDC hdc = useDevice ? fontHdc : data->hdc;
1609 bool stockFont = false;
1610 bool preferClearTypeAA = false;
1614 #if !defined(QT_NO_DIRECTWRITE)
1615 bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting)
1616 || (request.hintingPreference == QFont::PreferVerticalHinting);
1617 IDWriteFont *directWriteFont = 0;
1619 bool useDirectWrite = false;
1622 if (rawMode) { // will choose a stock font
1623 int f = SYSTEM_FONT;
1624 const QString fam = request.family.toLower();
1625 if (fam == QStringLiteral("default") || fam == QStringLiteral("system"))
1628 else if (fam == QStringLiteral("system_fixed"))
1629 f = SYSTEM_FIXED_FONT;
1630 else if (fam == QStringLiteral("ansi_fixed"))
1631 f = ANSI_FIXED_FONT;
1632 else if (fam == QStringLiteral("ansi_var"))
1634 else if (fam == QStringLiteral("device_default"))
1635 f = DEVICE_DEFAULT_FONT;
1636 else if (fam == QStringLiteral("oem_fixed"))
1639 else if (fam.at(0) == QLatin1Char('#'))
1640 f = fam.right(fam.length()-1).toInt();
1641 hfont = (HFONT)GetStockObject(f);
1643 qErrnoWarning("%s: GetStockObject failed", __FUNCTION__);
1644 hfont = QWindowsFontDatabase::systemFont();
1648 int hint = FF_DONTCARE;
1649 switch (request.styleHint) {
1650 case QFont::Helvetica:
1656 case QFont::Courier:
1659 case QFont::OldEnglish:
1660 hint = FF_DECORATIVE;
1669 lf.lfHeight = -qRound(request.pixelSize);
1671 lf.lfEscapement = 0;
1672 lf.lfOrientation = 0;
1673 if (request.weight == 50)
1674 lf.lfWeight = FW_DONTCARE;
1676 lf.lfWeight = (request.weight*900)/99;
1677 lf.lfItalic = request.style != QFont::StyleNormal;
1678 lf.lfCharSet = DEFAULT_CHARSET;
1680 int strat = OUT_DEFAULT_PRECIS;
1681 if (request.styleStrategy & QFont::PreferBitmap) {
1682 strat = OUT_RASTER_PRECIS;
1684 } else if (request.styleStrategy & QFont::PreferDevice) {
1685 strat = OUT_DEVICE_PRECIS;
1686 } else if (request.styleStrategy & QFont::PreferOutline) {
1687 strat = OUT_OUTLINE_PRECIS;
1688 } else if (request.styleStrategy & QFont::ForceOutline) {
1689 strat = OUT_TT_ONLY_PRECIS;
1693 lf.lfOutPrecision = strat;
1695 int qual = DEFAULT_QUALITY;
1697 if (request.styleStrategy & QFont::PreferMatch)
1698 qual = DRAFT_QUALITY;
1700 else if (request.styleStrategy & QFont::PreferQuality)
1701 qual = PROOF_QUALITY;
1704 if (request.styleStrategy & QFont::PreferAntialias) {
1705 if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) {
1706 qual = CLEARTYPE_QUALITY;
1707 preferClearTypeAA = true;
1709 qual = ANTIALIASED_QUALITY;
1711 } else if (request.styleStrategy & QFont::NoAntialias) {
1712 qual = NONANTIALIASED_QUALITY;
1715 lf.lfQuality = qual;
1717 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1718 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
1720 QString fam = request.family;
1723 fam = QStringLiteral("MS Sans Serif");
1725 if ((fam == QStringLiteral("MS Sans Serif"))
1726 && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
1727 fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
1729 if (fam == QStringLiteral("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
1730 fam = QStringLiteral("Courier New");
1732 memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
1734 hfont = CreateFontIndirect(&lf);
1736 qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
1738 stockFont = (hfont == 0);
1742 HGDIOBJ oldObj = SelectObject(hdc, hfont);
1745 res = GetTextMetrics(hdc, &tm);
1746 avWidth = tm.tmAveCharWidth;
1747 ttf = tm.tmPitchAndFamily & TMPF_TRUETYPE;
1748 SelectObject(hdc, oldObj);
1750 if (!ttf || !useDirectWrite) {
1751 useDirectWrite = false;
1753 if (hfont && (!ttf || request.stretch != 100)) {
1754 DeleteObject(hfont);
1756 qErrnoWarning("QFontEngine::loadEngine: GetTextMetrics failed");
1757 lf.lfWidth = avWidth * request.stretch/100;
1758 hfont = CreateFontIndirect(&lf);
1760 qErrnoWarning("%s: CreateFontIndirect with stretch failed", __FUNCTION__);
1765 hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
1770 hfont = (HFONT)GetStockObject(SYSTEM_FONT);
1776 #if !defined(QT_NO_DIRECTWRITE)
1778 // Default to false for DirectWrite (and re-enable once/if everything
1780 useDirectWrite = false;
1781 if (initDirectWrite(data.data())) {
1782 const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(QString::fromWCharArray(lf.lfFaceName));
1783 memcpy(lf.lfFaceName, nameSubstitute.utf16(),
1784 sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE));
1786 HRESULT hr = data->directWriteGdiInterop->CreateFontFromLOGFONT(
1790 qErrnoWarning("%s: CreateFontFromLOGFONT failed", __FUNCTION__);
1792 DeleteObject(hfont);
1793 useDirectWrite = true;
1800 QFontEngine *fe = 0;
1801 if (!useDirectWrite) {
1802 QWindowsFontEngine *few = new QWindowsFontEngine(request.family, hfont, stockFont, lf, data);
1803 few->setObjectName(QStringLiteral("QWindowsFontEngine_") + request.family);
1804 if (preferClearTypeAA)
1805 few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
1807 // Also check for OpenType tables when using complex scripts
1808 // ### TODO: This only works for scripts that require OpenType. More generally
1809 // for scripts that do not require OpenType we should just look at the list of
1810 // supported writing systems in the font's OS/2 table.
1811 if (scriptRequiresOpenType(script)) {
1812 HB_Face hbFace = few->harfbuzzFace();
1813 if (!hbFace || !hbFace->supported_scripts[script]) {
1814 qWarning(" OpenType support missing for script\n");
1820 few->initFontInfo(request, fontHdc, dpi);
1824 #if !defined(QT_NO_DIRECTWRITE)
1826 IDWriteFontFace *directWriteFontFace = NULL;
1827 HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace);
1828 if (SUCCEEDED(hr)) {
1829 QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
1832 fedw->initFontInfo(request, dpi, directWriteFont);
1833 fedw->setObjectName(QStringLiteral("QWindowsFontEngineDirectWrite_") + request.family);
1836 qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__);
1840 if (directWriteFont != 0)
1841 directWriteFont->Release();
1844 if(script == QUnicodeTables::Common
1845 && !(request.styleStrategy & QFont::NoFontMerging)) {
1847 if (!db.writingSystems(request.family).contains(QFontDatabase::Symbol)) {
1849 LANGID lid = GetUserDefaultLangID();
1850 switch( lid&0xff ) {
1851 case LANG_CHINESE: // Chinese (Taiwan)
1852 if ( lid == 0x0804 ) // Taiwan
1853 tryFonts = ch_TW_tryFonts;
1855 tryFonts = ch_CN_tryFonts;
1858 tryFonts = jp_tryFonts;
1861 tryFonts = kr_tryFonts;
1864 tryFonts = other_tryFonts;
1868 QStringList fm = QFontDatabase().families();
1869 QStringList list = family_list;
1870 const char **tf = tryFonts;
1872 if(fm.contains(QLatin1String(*tf)))
1873 list << QLatin1String(*tf);
1876 QFontEngine *mfe = new QWindowsMultiFontEngine(fe, list);
1877 mfe->setObjectName(QStringLiteral("QWindowsMultiFontEngine_") + request.family);
1878 mfe->fontDef = fe->fontDef;
1885 static inline int verticalDPI()
1887 return GetDeviceCaps(QWindowsContext::instance()->displayContext(), LOGPIXELSY);
1890 QFont QWindowsFontDatabase::systemDefaultFont()
1893 GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
1894 QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf);
1895 // "MS Shell Dlg 2" is the correct system font >= Win2k
1896 if (systemFont.family() == QStringLiteral("MS Shell Dlg"))
1897 systemFont.setFamily(QStringLiteral("MS Shell Dlg 2"));
1898 if (QWindowsContext::verboseFonts)
1899 qDebug() << __FUNCTION__ << systemFont;
1903 QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In)
1905 if (verticalDPI_In <= 0)
1906 verticalDPI_In = verticalDPI();
1907 QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
1908 qFont.setItalic(logFont.lfItalic);
1909 if (logFont.lfWeight != FW_DONTCARE)
1910 qFont.setWeight(weightFromInteger(logFont.lfWeight));
1911 const qreal logFontHeight = qAbs(logFont.lfHeight);
1912 qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
1913 qFont.setUnderline(false);
1914 qFont.setOverline(false);
1915 qFont.setStrikeOut(false);