1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwindowsfontdatabase_p.h"
41 #include "qwindowsfontdatabase_ft_p.h" // for default font
42 #include "qwindowsfontengine_p.h"
43 #include "qwindowsfontenginedirectwrite_p.h"
44 #include <QtCore/qt_windows.h>
45 
46 #include <QtGui/QFont>
47 #include <QtGui/QGuiApplication>
48 #include <QtGui/private/qhighdpiscaling_p.h>
49 
50 #include <QtCore/qmath.h>
51 #include <QtCore/QDebug>
52 #include <QtCore/QFile>
53 #include <QtCore/QtEndian>
54 #include <QtCore/QThreadStorage>
55 #include <QtCore/private/qsystemlibrary_p.h>
56 #include <QtCore/private/qwinregistry_p.h>
57 
58 #include <wchar.h>
59 
60 #if !defined(QT_NO_DIRECTWRITE)
61 #  if defined(QT_USE_DIRECTWRITE2)
62 #    include <dwrite_2.h>
63 #  else
64 #    include <dwrite.h>
65 #  endif
66 #  include <d2d1.h>
67 #endif
68 
69 QT_BEGIN_NAMESPACE
70 
71 Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
72 
73 #ifndef QT_NO_DIRECTWRITE
74 // ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711)
75 
76 typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
77 
resolveDWriteCreateFactory()78 static inline DWriteCreateFactoryType resolveDWriteCreateFactory()
79 {
80     QSystemLibrary library(QStringLiteral("dwrite"));
81     QFunctionPointer result = library.resolve("DWriteCreateFactory");
82     if (Q_UNLIKELY(!result)) {
83         qWarning("Unable to load dwrite.dll");
84         return nullptr;
85     }
86     return reinterpret_cast<DWriteCreateFactoryType>(result);
87 }
88 
createDirectWriteFactory(IDWriteFactory ** factory)89 static void createDirectWriteFactory(IDWriteFactory **factory)
90 {
91     *factory = nullptr;
92 
93     static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory();
94     if (!dWriteCreateFactory)
95         return;
96 
97     IUnknown *result = NULL;
98 #if defined(QT_USE_DIRECTWRITE2)
99     dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
100 #endif
101 
102     if (result == NULL) {
103         if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
104             qErrnoWarning("DWriteCreateFactory failed");
105             return;
106         }
107     }
108 
109     *factory = static_cast<IDWriteFactory *>(result);
110 }
111 
useDirectWrite(QFont::HintingPreference hintingPreference,const QString & familyName=QString (),bool isColorFont=false)112 static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
113                                   const QString &familyName = QString(),
114                                   bool isColorFont = false)
115 {
116     const unsigned options = QWindowsFontDatabase::fontOptions();
117     if (Q_UNLIKELY(options & QWindowsFontDatabase::DontUseDirectWriteFonts))
118         return false;
119 
120     // At some scales, GDI will misrender the MingLiU font, so we force use of
121     // DirectWrite to work around the issue.
122     if (Q_UNLIKELY(familyName.startsWith(QLatin1String("MingLiU"))))
123         return true;
124 
125     if (isColorFont)
126         return (options & QWindowsFontDatabase::DontUseColorFonts) == 0;
127 
128     return hintingPreference == QFont::PreferNoHinting
129         || hintingPreference == QFont::PreferVerticalHinting
130         || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting);
131 }
132 #endif // !QT_NO_DIRECTWRITE
133 
134 // Helper classes for creating font engines directly from font data
135 namespace {
136 
137 #   pragma pack(1)
138 
139     // Common structure for all formats of the "name" table
140     struct NameTable
141     {
142         quint16 format;
143         quint16 count;
144         quint16 stringOffset;
145     };
146 
147     struct NameRecord
148     {
149         quint16 platformID;
150         quint16 encodingID;
151         quint16 languageID;
152         quint16 nameID;
153         quint16 length;
154         quint16 offset;
155     };
156 
157     struct OffsetSubTable
158     {
159         quint32 scalerType;
160         quint16 numTables;
161         quint16 searchRange;
162         quint16 entrySelector;
163         quint16 rangeShift;
164     };
165 
166     struct TableDirectory
167     {
168         quint32 identifier;
169         quint32 checkSum;
170         quint32 offset;
171         quint32 length;
172     };
173 
174     struct OS2Table
175     {
176         quint16 version;
177         qint16  avgCharWidth;
178         quint16 weightClass;
179         quint16 widthClass;
180         quint16 type;
181         qint16  subscriptXSize;
182         qint16  subscriptYSize;
183         qint16  subscriptXOffset;
184         qint16  subscriptYOffset;
185         qint16  superscriptXSize;
186         qint16  superscriptYSize;
187         qint16  superscriptXOffset;
188         qint16  superscriptYOffset;
189         qint16  strikeOutSize;
190         qint16  strikeOutPosition;
191         qint16  familyClass;
192         quint8  panose[10];
193         quint32 unicodeRanges[4];
194         quint8  vendorID[4];
195         quint16 selection;
196         quint16 firstCharIndex;
197         quint16 lastCharIndex;
198         qint16  typoAscender;
199         qint16  typoDescender;
200         qint16  typoLineGap;
201         quint16 winAscent;
202         quint16 winDescent;
203         quint32 codepageRanges[2];
204         qint16  height;
205         qint16  capHeight;
206         quint16 defaultChar;
207         quint16 breakChar;
208         quint16 maxContext;
209     };
210 
211 #   pragma pack()
212 
213     class EmbeddedFont
214     {
215     public:
EmbeddedFont(const QByteArray & fontData)216         EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {}
217 
218         QString changeFamilyName(const QString &newFamilyName);
data() const219         QByteArray data() const { return m_fontData; }
220         TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
221         QString familyName(TableDirectory *nameTableDirectory = 0);
222 
223     private:
224         QByteArray m_fontData;
225     };
226 
tableDirectoryEntry(const QByteArray & tagName)227     TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
228     {
229         Q_ASSERT(tagName.size() == 4);
230         quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData()));
231         const size_t fontDataSize = m_fontData.size();
232         if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable)))
233             return 0;
234 
235         OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
236         TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
237 
238         const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables);
239         if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount))
240             return 0;
241 
242         TableDirectory *tableDirectoryEnd = tableDirectory + tableCount;
243         for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) {
244             if (entry->identifier == tagId)
245                 return entry;
246         }
247 
248         return 0;
249     }
250 
familyName(TableDirectory * nameTableDirectoryEntry)251     QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
252     {
253         QString name;
254 
255         if (nameTableDirectoryEntry == 0)
256             nameTableDirectoryEntry = tableDirectoryEntry("name");
257 
258         if (nameTableDirectoryEntry != 0) {
259             quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
260             if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable)))
261                 return QString();
262 
263             NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + offset);
264             NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
265 
266             quint16 nameTableCount = qFromBigEndian<quint16>(nameTable->count);
267             if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount))
268                 return QString();
269 
270             for (int i = 0; i < nameTableCount; ++i, ++nameRecord) {
271                 if (qFromBigEndian<quint16>(nameRecord->nameID) == 1
272                  && qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows
273                  && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English
274                     quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
275                     quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
276                     quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
277 
278                     if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
279                         return QString();
280 
281                     const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
282                                                         + stringOffset
283                                                         + nameOffset;
284 
285                     const quint16 *s = reinterpret_cast<const quint16 *>(ptr);
286                     const quint16 *e = s + nameLength / sizeof(quint16);
287                     while (s != e)
288                         name += QChar( qFromBigEndian<quint16>(*s++));
289                     break;
290                 }
291             }
292         }
293 
294         return name;
295     }
296 
changeFamilyName(const QString & newFamilyName)297     QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
298     {
299         TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
300         if (nameTableDirectoryEntry == 0)
301             return QString();
302 
303         QString oldFamilyName = familyName(nameTableDirectoryEntry);
304 
305         // Reserve size for name table header, five required name records and string
306         const int requiredRecordCount = 5;
307         quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
308 
309         int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
310         int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16));
311 
312         const QString regularString = QString::fromLatin1("Regular");
313         int regularStringSize = regularString.size() * int(sizeof(quint16));
314 
315         // Align table size of table to 32 bits (pad with 0)
316         int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
317 
318         QByteArray newNameTable(fullSize, char(0));
319 
320         {
321             NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
322             nameTable->count = qbswap<quint16>(requiredRecordCount);
323             nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
324 
325             NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
326             for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
327                 nameRecord->nameID = qbswap<quint16>(nameIds[i]);
328                 nameRecord->encodingID = qbswap<quint16>(1);
329                 nameRecord->languageID = qbswap<quint16>(0x0409);
330                 nameRecord->platformID = qbswap<quint16>(3);
331                 nameRecord->length = qbswap<quint16>(newFamilyNameSize);
332 
333                 // Special case for sub-family
334                 if (nameIds[i] == 4) {
335                     nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
336                     nameRecord->length = qbswap<quint16>(regularStringSize);
337                 }
338             }
339 
340             // nameRecord now points to string data
341             quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
342             const quint16 *sourceString = newFamilyName.utf16();
343             for (int i = 0; i < newFamilyName.size(); ++i)
344                 stringStorage[i] = qbswap<quint16>(sourceString[i]);
345             stringStorage += newFamilyName.size();
346 
347             sourceString = regularString.utf16();
348             for (int i = 0; i < regularString.size(); ++i)
349                 stringStorage[i] = qbswap<quint16>(sourceString[i]);
350         }
351 
352         quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
353         quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
354 
355         quint32 checkSum = 0;
356         while (p < tableEnd)
357             checkSum +=  qFromBigEndian<quint32>(*(p++));
358 
359         nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
360         nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
361         nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
362 
363         m_fontData.append(newNameTable);
364 
365         return oldFamilyName;
366     }
367 
368 #if !defined(QT_NO_DIRECTWRITE)
369 
370     class DirectWriteFontFileStream: public IDWriteFontFileStream
371     {
372         Q_DISABLE_COPY(DirectWriteFontFileStream)
373     public:
DirectWriteFontFileStream(const QByteArray & fontData)374         DirectWriteFontFileStream(const QByteArray &fontData)
375             : m_fontData(fontData)
376             , m_referenceCount(0)
377         {
378         }
~DirectWriteFontFileStream()379         virtual ~DirectWriteFontFileStream()
380         {
381         }
382 
383         HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
384         ULONG STDMETHODCALLTYPE AddRef();
385         ULONG STDMETHODCALLTYPE Release();
386 
387         HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
388                                                    UINT64 fragmentSize, OUT void **fragmentContext);
389         void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext);
390         HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize);
391         HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime);
392 
393     private:
394         QByteArray m_fontData;
395         ULONG m_referenceCount;
396     };
397 
QueryInterface(REFIID iid,void ** object)398     HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
399     {
400         if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
401             *object = this;
402             AddRef();
403             return S_OK;
404         } else {
405             *object = NULL;
406             return E_NOINTERFACE;
407         }
408     }
409 
AddRef()410     ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
411     {
412         return InterlockedIncrement(&m_referenceCount);
413     }
414 
Release()415     ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
416     {
417         ULONG newCount = InterlockedDecrement(&m_referenceCount);
418         if (newCount == 0)
419             delete this;
420         return newCount;
421     }
422 
ReadFileFragment(const void ** fragmentStart,UINT64 fileOffset,UINT64 fragmentSize,OUT void ** fragmentContext)423     HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
424         const void **fragmentStart,
425         UINT64 fileOffset,
426         UINT64 fragmentSize,
427         OUT void **fragmentContext)
428     {
429         *fragmentContext = NULL;
430         if (fileOffset + fragmentSize <= quint64(m_fontData.size())) {
431             *fragmentStart = m_fontData.data() + fileOffset;
432             return S_OK;
433         } else {
434             *fragmentStart = NULL;
435             return E_FAIL;
436         }
437     }
438 
ReleaseFileFragment(void *)439     void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
440     {
441     }
442 
GetFileSize(UINT64 * fileSize)443     HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
444     {
445         *fileSize = m_fontData.size();
446         return S_OK;
447     }
448 
GetLastWriteTime(UINT64 * lastWriteTime)449     HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
450     {
451         *lastWriteTime = 0;
452         return E_NOTIMPL;
453     }
454 
455     class DirectWriteFontFileLoader: public IDWriteFontFileLoader
456     {
457     public:
DirectWriteFontFileLoader()458         DirectWriteFontFileLoader() : m_referenceCount(0) {}
~DirectWriteFontFileLoader()459         virtual ~DirectWriteFontFileLoader()
460         {
461         }
462 
addKey(const void * key,const QByteArray & fontData)463         inline void addKey(const void *key, const QByteArray &fontData)
464         {
465             Q_ASSERT(!m_fontDatas.contains(key));
466             m_fontDatas.insert(key, fontData);
467         }
468 
removeKey(const void * key)469         inline void removeKey(const void *key)
470         {
471             m_fontDatas.remove(key);
472         }
473 
474         HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
475         ULONG STDMETHODCALLTYPE AddRef();
476         ULONG STDMETHODCALLTYPE Release();
477 
478         HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
479                                                       UINT32 fontFileReferenceKeySize,
480                                                       OUT IDWriteFontFileStream **fontFileStream);
481 
482     private:
483         ULONG m_referenceCount;
484         QHash<const void *, QByteArray> m_fontDatas;
485     };
486 
QueryInterface(const IID & iid,void ** object)487     HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
488                                                                         void **object)
489     {
490         if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
491             *object = this;
492             AddRef();
493             return S_OK;
494         } else {
495             *object = NULL;
496             return E_NOINTERFACE;
497         }
498     }
499 
AddRef()500     ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
501     {
502         return InterlockedIncrement(&m_referenceCount);
503     }
504 
Release()505     ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
506     {
507         ULONG newCount = InterlockedDecrement(&m_referenceCount);
508         if (newCount == 0)
509             delete this;
510         return newCount;
511     }
512 
CreateStreamFromKey(void const * fontFileReferenceKey,UINT32 fontFileReferenceKeySize,IDWriteFontFileStream ** fontFileStream)513     HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
514         void const *fontFileReferenceKey,
515         UINT32 fontFileReferenceKeySize,
516         IDWriteFontFileStream **fontFileStream)
517     {
518         Q_UNUSED(fontFileReferenceKeySize);
519 
520         if (fontFileReferenceKeySize != sizeof(const void *)) {
521             qWarning("%s: Wrong key size", __FUNCTION__);
522             return E_FAIL;
523         }
524 
525         const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
526         *fontFileStream = NULL;
527         auto it = m_fontDatas.constFind(key);
528         if (it == m_fontDatas.constEnd())
529             return E_FAIL;
530 
531         QByteArray fontData = it.value();
532         DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
533         stream->AddRef();
534         *fontFileStream = stream;
535 
536         return S_OK;
537     }
538 
539     class CustomFontFileLoader
540     {
541     public:
CustomFontFileLoader()542         CustomFontFileLoader() : m_directWriteFontFileLoader(nullptr)
543         {
544             createDirectWriteFactory(&m_directWriteFactory);
545 
546             if (m_directWriteFactory) {
547                 m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
548                 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
549             }
550         }
551 
~CustomFontFileLoader()552         ~CustomFontFileLoader()
553         {
554             if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
555                 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
556 
557             if (m_directWriteFactory != 0)
558                 m_directWriteFactory->Release();
559         }
560 
addKey(const void * key,const QByteArray & fontData)561         void addKey(const void *key, const QByteArray &fontData)
562         {
563             if (m_directWriteFontFileLoader != 0)
564                 m_directWriteFontFileLoader->addKey(key, fontData);
565         }
566 
removeKey(const void * key)567         void removeKey(const void *key)
568         {
569             if (m_directWriteFontFileLoader != 0)
570                 m_directWriteFontFileLoader->removeKey(key);
571         }
572 
loader() const573         IDWriteFontFileLoader *loader() const
574         {
575             return m_directWriteFontFileLoader;
576         }
577 
578     private:
579         IDWriteFactory *m_directWriteFactory;
580         DirectWriteFontFileLoader *m_directWriteFontFileLoader;
581     };
582 
583 #endif
584 
585 } // Anonymous namespace
586 
587 /*!
588     \struct QWindowsFontEngineData
589     \brief Static constant data shared by the font engines.
590 */
591 
QWindowsFontEngineData()592 QWindowsFontEngineData::QWindowsFontEngineData()
593     : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma())
594 {
595     // from qapplication_win.cpp
596     UINT result = 0;
597     if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0))
598         clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE);
599 
600     const qreal gray_gamma = 2.31;
601     for (int i=0; i<256; ++i)
602         pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
603 
604     HDC displayDC = GetDC(0);
605     hdc = CreateCompatibleDC(displayDC);
606     ReleaseDC(0, displayDC);
607 }
608 
609 unsigned QWindowsFontDatabase::m_fontOptions = 0;
610 
setFontOptions(unsigned options)611 void QWindowsFontDatabase::setFontOptions(unsigned options)
612 {
613     m_fontOptions = options & (QWindowsFontDatabase::DontUseDirectWriteFonts |
614                                QWindowsFontDatabase::DontUseColorFonts);
615 }
616 
fontOptions()617 unsigned QWindowsFontDatabase::fontOptions()
618 {
619     return m_fontOptions;
620 }
621 
~QWindowsFontEngineData()622 QWindowsFontEngineData::~QWindowsFontEngineData()
623 {
624     if (hdc)
625         DeleteDC(hdc);
626 #if !defined(QT_NO_DIRECTWRITE)
627     if (directWriteGdiInterop)
628         directWriteGdiInterop->Release();
629     if (directWriteFactory)
630         directWriteFactory->Release();
631 #endif
632 }
633 
fontSmoothingGamma()634 qreal QWindowsFontDatabase::fontSmoothingGamma()
635 {
636     int winSmooth;
637     qreal result = 1;
638     if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0))
639         result = qreal(winSmooth) / qreal(1000.0);
640 
641     // Safeguard ourselves against corrupt registry values...
642     if (result > 5 || result < 1)
643         result = qreal(1.4);
644     return result;
645 }
646 
647 #if !defined(QT_NO_DIRECTWRITE)
initDirectWrite(QWindowsFontEngineData * d)648 static inline bool initDirectWrite(QWindowsFontEngineData *d)
649 {
650     if (!d->directWriteFactory) {
651         createDirectWriteFactory(&d->directWriteFactory);
652         if (!d->directWriteFactory)
653             return false;
654     }
655     if (!d->directWriteGdiInterop) {
656         const HRESULT  hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
657         if (FAILED(hr)) {
658             qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__);
659             return false;
660         }
661     }
662     return true;
663 }
664 
665 #endif // !defined(QT_NO_DIRECTWRITE)
666 
667 /*!
668     \class QWindowsFontDatabase
669     \brief Font database for Windows
670 
671     \note The Qt 4.8 WIndows font database employed a mechanism of
672     delayed population of the database again passing a font name
673     to EnumFontFamiliesEx(), working around the fact that
674     EnumFontFamiliesEx() does not list all fonts by default.
675     This should be introduced to QPA as well?
676 
677     \internal
678 */
679 
680 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug d,const QFontDef & def)681 QDebug operator<<(QDebug d, const QFontDef &def)
682 {
683     QDebugStateSaver saver(d);
684     d.nospace();
685     d.noquote();
686     d << "QFontDef(Family=\"" << def.family << '"';
687     if (!def.styleName.isEmpty())
688         d << ", stylename=" << def.styleName;
689     d << ", pointsize=" << def.pointSize << ", pixelsize=" << def.pixelSize
690         << ", styleHint=" << def.styleHint << ", weight=" << def.weight
691         << ", stretch=" << def.stretch << ", hintingPreference="
692         << def.hintingPreference << ')';
693     return d;
694 }
695 
operator <<(QDebug d,const LOGFONT & lf)696 QDebug operator<<(QDebug d, const LOGFONT &lf)
697 {
698     QDebugStateSaver saver(d);
699     d.nospace();
700     d.noquote();
701     d << "LOGFONT(\"" << QString::fromWCharArray(lf.lfFaceName)
702         << "\", lfWidth=" << lf.lfWidth << ", lfHeight=" << lf.lfHeight << ')';
703     return d;
704 }
705 #endif // !QT_NO_DEBUG_STREAM
706 
writingSystemFromCharSet(uchar charSet)707 static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet)
708 {
709     switch (charSet) {
710     case ANSI_CHARSET:
711     case EASTEUROPE_CHARSET:
712     case BALTIC_CHARSET:
713     case TURKISH_CHARSET:
714         return QFontDatabase::Latin;
715     case GREEK_CHARSET:
716         return QFontDatabase::Greek;
717     case RUSSIAN_CHARSET:
718         return QFontDatabase::Cyrillic;
719     case HEBREW_CHARSET:
720         return QFontDatabase::Hebrew;
721     case ARABIC_CHARSET:
722         return QFontDatabase::Arabic;
723     case THAI_CHARSET:
724         return QFontDatabase::Thai;
725     case GB2312_CHARSET:
726         return QFontDatabase::SimplifiedChinese;
727     case CHINESEBIG5_CHARSET:
728         return QFontDatabase::TraditionalChinese;
729     case SHIFTJIS_CHARSET:
730         return QFontDatabase::Japanese;
731     case HANGUL_CHARSET:
732     case JOHAB_CHARSET:
733         return QFontDatabase::Korean;
734     case VIETNAMESE_CHARSET:
735         return QFontDatabase::Vietnamese;
736     case SYMBOL_CHARSET:
737         return QFontDatabase::Symbol;
738     default:
739         break;
740     }
741     return QFontDatabase::Any;
742 }
743 
744 #ifdef MAKE_TAG
745 #undef MAKE_TAG
746 #endif
747 // GetFontData expects the tags in little endian ;(
748 #define MAKE_TAG(ch1, ch2, ch3, ch4) (\
749     (((quint32)(ch4)) << 24) | \
750     (((quint32)(ch3)) << 16) | \
751     (((quint32)(ch2)) << 8) | \
752     ((quint32)(ch1)) \
753     )
754 
qt_localizedName(const QString & name)755 bool qt_localizedName(const QString &name)
756 {
757     const QChar *c = name.unicode();
758     for (int i = 0; i < name.length(); ++i) {
759         if (c[i].unicode() >= 0x100)
760             return true;
761     }
762     return false;
763 }
764 
765 namespace {
766 
readName(bool unicode,const uchar * string,int length)767 static QString readName(bool unicode, const uchar *string, int length)
768 {
769     QString out;
770     if (unicode) {
771         // utf16
772 
773         length /= 2;
774         out.resize(length);
775         QChar *uc = out.data();
776         for (int i = 0; i < length; ++i)
777             uc[i] = qt_getUShort(string + 2*i);
778     } else {
779         // Apple Roman
780 
781         out.resize(length);
782         QChar *uc = out.data();
783         for (int i = 0; i < length; ++i)
784             uc[i] = QLatin1Char(char(string[i]));
785     }
786     return out;
787 }
788 
789 enum FieldTypeValue {
790     FamilyId = 1,
791     StyleId = 2,
792     PreferredFamilyId = 16,
793     PreferredStyleId = 17,
794 };
795 
796 enum PlatformFieldValue {
797     PlatformId_Unicode = 0,
798     PlatformId_Apple = 1,
799     PlatformId_Microsoft = 3
800 };
801 
qt_getCanonicalFontNames(const uchar * table,quint32 bytes)802 QFontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes)
803 {
804     QFontNames out;
805     const int NameRecordSize = 12;
806     const int MS_LangIdEnglish = 0x009;
807 
808     // get the name table
809     quint16 count;
810     quint16 string_offset;
811     const unsigned char *names;
812 
813     if (bytes < 8)
814         return out;
815 
816     if (qt_getUShort(table) != 0)
817         return out;
818 
819     count = qt_getUShort(table + 2);
820     string_offset = qt_getUShort(table + 4);
821     names = table + 6;
822 
823     if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
824         return out;
825 
826     enum PlatformIdType {
827         NotFound = 0,
828         Unicode = 1,
829         Apple = 2,
830         Microsoft = 3
831     };
832 
833     PlatformIdType idStatus[4] = { NotFound, NotFound, NotFound, NotFound };
834     int ids[4] = { -1, -1, -1, -1 };
835 
836     for (int i = 0; i < count; ++i) {
837         // search for the correct name entries
838 
839         quint16 platform_id = qt_getUShort(names + i*NameRecordSize);
840         quint16 encoding_id = qt_getUShort(names + 2 + i*NameRecordSize);
841         quint16 language_id = qt_getUShort(names + 4 + i*NameRecordSize);
842         quint16 name_id = qt_getUShort(names + 6 + i*NameRecordSize);
843 
844         PlatformIdType *idType = nullptr;
845         int *id = nullptr;
846 
847         switch (name_id) {
848         case FamilyId:
849             idType = &idStatus[0];
850             id = &ids[0];
851             break;
852         case StyleId:
853             idType = &idStatus[1];
854             id = &ids[1];
855             break;
856         case PreferredFamilyId:
857             idType = &idStatus[2];
858             id = &ids[2];
859             break;
860         case PreferredStyleId:
861             idType = &idStatus[3];
862             id = &ids[3];
863             break;
864         default:
865             continue;
866         }
867 
868         quint16 length = qt_getUShort(names + 8 + i*NameRecordSize);
869         quint16 offset = qt_getUShort(names + 10 + i*NameRecordSize);
870         if (DWORD(string_offset + offset + length) > bytes)
871             continue;
872 
873         if ((platform_id == PlatformId_Microsoft
874             && (encoding_id == 0 || encoding_id == 1))
875             && ((language_id & 0x3ff) == MS_LangIdEnglish
876                 || *idType < Microsoft)) {
877             *id = i;
878             *idType = Microsoft;
879         }
880         // not sure if encoding id 4 for Unicode is utf16 or ucs4...
881         else if (platform_id == PlatformId_Unicode && encoding_id < 4 && *idType < Unicode) {
882             *id = i;
883             *idType = Unicode;
884         }
885         else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0 && *idType < Apple) {
886             *id = i;
887             *idType = Apple;
888         }
889     }
890 
891     QString strings[4];
892     for (int i = 0; i < 4; ++i) {
893         if (idStatus[i] == NotFound)
894             continue;
895         int id = ids[i];
896         quint16 length = qt_getUShort(names +  8 + id * NameRecordSize);
897         quint16 offset = qt_getUShort(names + 10 + id * NameRecordSize);
898         const unsigned char *string = table + string_offset + offset;
899         strings[i] = readName(idStatus[i] != Apple, string, length);
900     }
901 
902     out.name = strings[0];
903     out.style = strings[1];
904     out.preferredName = strings[2];
905     out.preferredStyle = strings[3];
906     return out;
907 }
908 
909 } // namespace
910 
qt_getEnglishName(const QString & familyName,bool includeStyle)911 QString qt_getEnglishName(const QString &familyName, bool includeStyle)
912 {
913     QString i18n_name;
914     QString faceName = familyName;
915     faceName.truncate(LF_FACESIZE - 1);
916 
917     HDC hdc = GetDC( 0 );
918     LOGFONT lf;
919     memset(&lf, 0, sizeof(LOGFONT));
920     faceName.toWCharArray(lf.lfFaceName);
921     lf.lfFaceName[faceName.size()] = 0;
922     lf.lfCharSet = DEFAULT_CHARSET;
923     HFONT hfont = CreateFontIndirect(&lf);
924 
925     if (!hfont) {
926         ReleaseDC(0, hdc);
927         return QString();
928     }
929 
930     HGDIOBJ oldobj = SelectObject( hdc, hfont );
931 
932     const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
933 
934     // get the name table
935     unsigned char *table = 0;
936 
937     DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
938     if ( bytes == GDI_ERROR ) {
939         // ### Unused variable
940         // int err = GetLastError();
941         goto error;
942     }
943 
944     table = new unsigned char[bytes];
945     GetFontData(hdc, name_tag, 0, table, bytes);
946     if ( bytes == GDI_ERROR )
947         goto error;
948 
949     {
950         const QFontNames names = qt_getCanonicalFontNames(table, bytes);
951         i18n_name = names.name;
952         if (includeStyle)
953             i18n_name += QLatin1Char(' ') + names.style;
954     }
955 error:
956     delete [] table;
957     SelectObject( hdc, oldobj );
958     DeleteObject( hfont );
959     ReleaseDC( 0, hdc );
960 
961     //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
962     return i18n_name;
963 }
964 
965 // Note this duplicates parts of qt_getEnglishName, we should try to unify the two functions.
qt_getCanonicalFontNames(const LOGFONT & lf)966 QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
967 {
968     QFontNames fontNames;
969     HDC hdc = GetDC(0);
970     HFONT hfont = CreateFontIndirect(&lf);
971 
972     if (!hfont) {
973         ReleaseDC(0, hdc);
974         return fontNames;
975     }
976 
977     HGDIOBJ oldobj = SelectObject(hdc, hfont);
978 
979     // get the name table
980     QByteArray table;
981     const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e');
982     DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0);
983     if (bytes != GDI_ERROR) {
984         table.resize(bytes);
985 
986         if (GetFontData(hdc, name_tag, 0, table.data(), bytes) != GDI_ERROR)
987             fontNames = qt_getCanonicalFontNames(reinterpret_cast<const uchar*>(table.constData()), bytes);
988     }
989 
990     SelectObject(hdc, oldobj);
991     DeleteObject(hfont);
992     ReleaseDC(0, hdc);
993 
994     return fontNames;
995 }
996 
createFontFile(const QString & faceName)997 static QChar *createFontFile(const QString &faceName)
998 {
999     QChar *faceNamePtr = nullptr;
1000     if (!faceName.isEmpty()) {
1001         const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1);
1002         faceNamePtr = new QChar[nameLength + 1];
1003         memcpy(static_cast<void *>(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength);
1004         faceNamePtr[nameLength] = 0;
1005     }
1006     return faceNamePtr;
1007 }
1008 
1009 namespace {
1010     struct StoreFontPayload {
StoreFontPayload__anonf565e9d30311::StoreFontPayload1011         StoreFontPayload(const QString &family,
1012                          QWindowsFontDatabase *fontDatabase)
1013             : populatedFontFamily(family)
1014             , windowsFontDatabase(fontDatabase)
1015         {}
1016 
1017         QString populatedFontFamily;
1018         QSet<QPair<QString,QString> > foundFontAndStyles;
1019         QWindowsFontDatabase *windowsFontDatabase;
1020     };
1021 }
1022 
addFontToDatabase(QString familyName,QString styleName,const LOGFONT & logFont,const TEXTMETRIC * textmetric,const FONTSIGNATURE * signature,int type,StoreFontPayload * sfp)1023 static bool addFontToDatabase(QString familyName,
1024                               QString styleName,
1025                               const LOGFONT &logFont,
1026                               const TEXTMETRIC *textmetric,
1027                               const FONTSIGNATURE *signature,
1028                               int type,
1029                               StoreFontPayload *sfp)
1030 {
1031     // the "@family" fonts are just the same as "family". Ignore them.
1032     if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_")))
1033         return false;
1034 
1035     uchar charSet = logFont.lfCharSet;
1036 
1037     static const int SMOOTH_SCALABLE = 0xffff;
1038     const QString foundryName; // No such concept.
1039     const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH);
1040     const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
1041     const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
1042     const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight;
1043     const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
1044     const bool antialias = false;
1045     const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight);
1046     const QFont::Stretch stretch = QFont::Unstretched;
1047 
1048 #ifndef QT_NO_DEBUG_OUTPUT
1049     if (lcQpaFonts().isDebugEnabled()) {
1050         QString message;
1051         QTextStream str(&message);
1052         str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf;
1053         if (type & DEVICE_FONTTYPE)
1054             str << " DEVICE";
1055         if (type & RASTER_FONTTYPE)
1056             str << " RASTER";
1057         if (type & TRUETYPE_FONTTYPE)
1058             str << " TRUETYPE";
1059         str << " scalable=" << scalable << " Size=" << size
1060                 << " Style=" << style << " Weight=" << weight
1061                 << " stretch=" << stretch;
1062         qCDebug(lcQpaFonts) << message;
1063     }
1064 #endif
1065     QString englishName;
1066     QString faceName;
1067 
1068     QString subFamilyName;
1069     QString subFamilyStyle;
1070     // Look-up names registered in the font
1071     QFontNames canonicalNames = qt_getCanonicalFontNames(logFont);
1072     if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty())
1073         englishName = canonicalNames.name;
1074     if (!canonicalNames.preferredName.isEmpty()) {
1075         subFamilyName = familyName;
1076         subFamilyStyle = styleName;
1077         faceName = familyName; // Remember the original name for later lookups
1078         familyName = canonicalNames.preferredName;
1079         styleName = canonicalNames.preferredStyle;
1080     }
1081 
1082     QSupportedWritingSystems writingSystems;
1083     if (type & TRUETYPE_FONTTYPE) {
1084         Q_ASSERT(signature);
1085         quint32 unicodeRange[4] = {
1086             signature->fsUsb[0], signature->fsUsb[1],
1087             signature->fsUsb[2], signature->fsUsb[3]
1088         };
1089         quint32 codePageRange[2] = {
1090             signature->fsCsb[0], signature->fsCsb[1]
1091         };
1092         writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
1093         // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
1094         // the symbol for Baht, and Windows thus reports that it supports the Thai script.
1095         // Since it's the default UI font on this platform, most widgets will be unable to
1096         // display Thai text by default. As a temporary work around, we special case Segoe UI
1097         // and remove the Thai script from its list of supported writing systems.
1098         if (writingSystems.supported(QFontDatabase::Thai) &&
1099                 familyName == QLatin1String("Segoe UI"))
1100             writingSystems.setSupported(QFontDatabase::Thai, false);
1101     } else {
1102         const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet);
1103         if (ws != QFontDatabase::Any)
1104             writingSystems.setSupported(ws);
1105     }
1106 
1107     // We came here from populating a different font family, so we have
1108     // to ensure the entire typographic family is populated before we
1109     // mark it as such inside registerFont()
1110     if (!subFamilyName.isEmpty()
1111             && familyName != subFamilyName
1112             && sfp->populatedFontFamily != familyName
1113             && !QPlatformFontDatabase::isFamilyPopulated(familyName)) {
1114         sfp->windowsFontDatabase->populateFamily(familyName);
1115     }
1116 
1117     QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
1118                                         style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
1119 
1120     // add fonts windows can generate for us:
1121     if (weight <= QFont::DemiBold && styleName.isEmpty())
1122         QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
1123                                             style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
1124     if (style != QFont::StyleItalic && styleName.isEmpty())
1125         QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight,
1126                                             QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
1127     if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
1128         QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
1129                                             QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
1130 
1131     if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
1132         QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
1133                                             style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
1134     }
1135 
1136     if (!englishName.isEmpty() && englishName != familyName)
1137         QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName);
1138 
1139     return true;
1140 }
1141 
storeFont(const LOGFONT * logFont,const TEXTMETRIC * textmetric,DWORD type,LPARAM lparam)1142 static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
1143                                      DWORD type, LPARAM lparam)
1144 {
1145     const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
1146     const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
1147     const QString styleName = QString::fromWCharArray(f->elfStyle);
1148 
1149     // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according
1150     // to the documentation is identical to a TEXTMETRIC except for the last four
1151     // members, which we don't use anyway
1152     const FONTSIGNATURE *signature = nullptr;
1153     StoreFontPayload *sfp = reinterpret_cast<StoreFontPayload *>(lparam);
1154     Q_ASSERT(sfp != nullptr);
1155     if (type & TRUETYPE_FONTTYPE) {
1156         signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig;
1157         // We get a callback for each script-type supported, but we register them all
1158         // at once using the signature, so we only need one call to addFontToDatabase().
1159         QPair<QString,QString> fontAndStyle(familyName, styleName);
1160         if (sfp->foundFontAndStyles.contains(fontAndStyle))
1161             return 1;
1162         sfp->foundFontAndStyles.insert(fontAndStyle);
1163     }
1164     addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp);
1165 
1166     // keep on enumerating
1167     return 1;
1168 }
1169 
populateFamilyAliases(const QString & missingFamily)1170 bool QWindowsFontDatabase::populateFamilyAliases(const QString &missingFamily)
1171 {
1172     Q_UNUSED(missingFamily);
1173 
1174     if (m_hasPopulatedAliases)
1175         return false;
1176 
1177     QStringList families = QFontDatabase().families();
1178     for (const QString &family : families)
1179         populateFamily(family);
1180     m_hasPopulatedAliases = true;
1181 
1182     return true;
1183 }
1184 
populateFamily(const QString & familyName)1185 void QWindowsFontDatabase::populateFamily(const QString &familyName)
1186 {
1187     qCDebug(lcQpaFonts) << familyName;
1188     if (familyName.size() >= LF_FACESIZE) {
1189         qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\'';
1190         return;
1191     }
1192     HDC dummy = GetDC(0);
1193     LOGFONT lf;
1194     lf.lfCharSet = DEFAULT_CHARSET;
1195     familyName.toWCharArray(lf.lfFaceName);
1196     lf.lfFaceName[familyName.size()] = 0;
1197     lf.lfPitchAndFamily = 0;
1198     StoreFontPayload sfp(familyName, this);
1199     EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&sfp), 0);
1200     ReleaseDC(0, dummy);
1201 }
1202 
populateFontFamilies(const LOGFONT * logFont,const TEXTMETRIC * textmetric,DWORD,LPARAM)1203 static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
1204                                                 DWORD, LPARAM)
1205 {
1206     // the "@family" fonts are just the same as "family". Ignore them.
1207     const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
1208     const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
1209     if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
1210         const QString faceName = QString::fromWCharArray(faceNameW);
1211         QPlatformFontDatabase::registerFontFamily(faceName);
1212         // Register current font's english name as alias
1213         const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
1214         if (ttf && qt_localizedName(faceName)) {
1215             const QString englishName = qt_getEnglishName(faceName);
1216             if (!englishName.isEmpty())
1217                 QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName);
1218         }
1219     }
1220     return 1; // continue
1221 }
1222 
addDefaultEUDCFont()1223 void QWindowsFontDatabase::addDefaultEUDCFont()
1224 {
1225     const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)")
1226                          .stringValue(L"SystemDefaultEUDCFont");
1227     if (!path.isEmpty()) {
1228         QFile file(path);
1229         if (!file.open(QIODevice::ReadOnly)) {
1230             qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << path;
1231             return;
1232         }
1233 
1234         m_eudcFonts = addApplicationFont(file.readAll(), path);
1235     }
1236 }
1237 
populateFontDatabase()1238 void QWindowsFontDatabase::populateFontDatabase()
1239 {
1240     removeApplicationFonts();
1241     HDC dummy = GetDC(0);
1242     LOGFONT lf;
1243     lf.lfCharSet = DEFAULT_CHARSET;
1244     lf.lfFaceName[0] = 0;
1245     lf.lfPitchAndFamily = 0;
1246     EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
1247     ReleaseDC(0, dummy);
1248     // Work around EnumFontFamiliesEx() not listing the system font.
1249     QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family();
1250     if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
1251         QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
1252     addDefaultEUDCFont();
1253 }
1254 
1255 typedef QSharedPointer<QWindowsFontEngineData> QWindowsFontEngineDataPtr;
1256 
1257 typedef QThreadStorage<QWindowsFontEngineDataPtr> FontEngineThreadLocalData;
1258 
Q_GLOBAL_STATIC(FontEngineThreadLocalData,fontEngineThreadLocalData)1259 Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
1260 
1261 QSharedPointer<QWindowsFontEngineData> sharedFontData()
1262 {
1263     FontEngineThreadLocalData *data = fontEngineThreadLocalData();
1264     if (!data->hasLocalData())
1265         data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
1266     return data->localData();
1267 }
1268 
QWindowsFontDatabase()1269 QWindowsFontDatabase::QWindowsFontDatabase()
1270 {
1271     // Properties accessed by QWin32PrintEngine (Qt Print Support)
1272     static const int hfontMetaTypeId = qRegisterMetaType<HFONT>();
1273     static const int logFontMetaTypeId = qRegisterMetaType<LOGFONT>();
1274     Q_UNUSED(hfontMetaTypeId)
1275     Q_UNUSED(logFontMetaTypeId)
1276 
1277     if (lcQpaFonts().isDebugEnabled()) {
1278         const QWindowsFontEngineDataPtr data = sharedFontData();
1279         qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
1280             << data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma;
1281     }
1282 }
1283 
~QWindowsFontDatabase()1284 QWindowsFontDatabase::~QWindowsFontDatabase()
1285 {
1286     removeApplicationFonts();
1287 }
1288 
fontEngine(const QFontDef & fontDef,void * handle)1289 QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
1290 {
1291     const QString faceName(static_cast<const QChar*>(handle));
1292     QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
1293                                                          defaultVerticalDPI(),
1294                                                          sharedFontData());
1295     qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle;
1296     return fe;
1297 }
1298 
fontEngine(const QByteArray & fontData,qreal pixelSize,QFont::HintingPreference hintingPreference)1299 QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
1300 {
1301     EmbeddedFont font(fontData);
1302     QFontEngine *fontEngine = 0;
1303 
1304 #if !defined(QT_NO_DIRECTWRITE)
1305     if (!useDirectWrite(hintingPreference))
1306 #endif
1307     {
1308         GUID guid;
1309         CoCreateGuid(&guid);
1310 
1311 QT_WARNING_PUSH
1312 QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
1313         QString uniqueFamilyName = QLatin1Char('f')
1314                 + QString::number(guid.Data1, 36) + QLatin1Char('-')
1315                 + QString::number(guid.Data2, 36) + QLatin1Char('-')
1316                 + QString::number(guid.Data3, 36) + QLatin1Char('-')
1317                 + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
1318 QT_WARNING_POP
1319 
1320         QString actualFontName = font.changeFamilyName(uniqueFamilyName);
1321         if (actualFontName.isEmpty()) {
1322             qWarning("%s: Can't change family name of font", __FUNCTION__);
1323             return 0;
1324         }
1325 
1326         DWORD count = 0;
1327         QByteArray newFontData = font.data();
1328         HANDLE fontHandle =
1329             AddFontMemResourceEx(const_cast<char *>(newFontData.constData()),
1330                                  DWORD(newFontData.size()), 0, &count);
1331         if (count == 0 && fontHandle != 0) {
1332             RemoveFontMemResourceEx(fontHandle);
1333             fontHandle = 0;
1334         }
1335 
1336         if (fontHandle == 0) {
1337             qWarning("%s: AddFontMemResourceEx failed", __FUNCTION__);
1338         } else {
1339             QFontDef request;
1340             request.family = uniqueFamilyName;
1341             request.pixelSize = pixelSize;
1342             request.styleStrategy = QFont::PreferMatch;
1343             request.hintingPreference = hintingPreference;
1344             request.stretch = QFont::Unstretched;
1345 
1346             fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
1347                                                             defaultVerticalDPI(),
1348                                                             sharedFontData());
1349 
1350             if (fontEngine) {
1351                 if (request.family != fontEngine->fontDef.family) {
1352                     qWarning("%s: Failed to load font. Got fallback instead: %s",
1353                              __FUNCTION__, qPrintable(fontEngine->fontDef.family));
1354                     if (fontEngine->ref.loadRelaxed() == 0)
1355                         delete fontEngine;
1356                     fontEngine = 0;
1357                 } else {
1358                     Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
1359 
1360                     // Override the generated font name
1361                     switch (fontEngine->type()) {
1362                     case QFontEngine::Win:
1363                         static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1364                         fontEngine->fontDef.family = actualFontName;
1365                         break;
1366 
1367 #if !defined(QT_NO_DIRECTWRITE)
1368                     case QFontEngine::DirectWrite:
1369                         static_cast<QWindowsFontEngineDirectWrite *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
1370                         fontEngine->fontDef.family = actualFontName;
1371                         break;
1372 #endif // !QT_NO_DIRECTWRITE
1373 
1374                     default:
1375                         Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine.");
1376                     }
1377 
1378                     UniqueFontData uniqueData;
1379                     uniqueData.handle = fontHandle;
1380                     uniqueData.refCount.ref();
1381                     m_uniqueFontData[uniqueFamilyName] = uniqueData;
1382                 }
1383             } else {
1384                 RemoveFontMemResourceEx(fontHandle);
1385             }
1386         }
1387     }
1388 #if !defined(QT_NO_DIRECTWRITE)
1389     else {
1390         CustomFontFileLoader fontFileLoader;
1391         fontFileLoader.addKey(this, fontData);
1392 
1393         QSharedPointer<QWindowsFontEngineData> fontEngineData = sharedFontData();
1394         if (!initDirectWrite(fontEngineData.data()))
1395             return 0;
1396 
1397         IDWriteFontFile *fontFile = 0;
1398         void *key = this;
1399 
1400         HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
1401                                                                                          sizeof(void *),
1402                                                                                          fontFileLoader.loader(),
1403                                                                                          &fontFile);
1404         if (FAILED(hres)) {
1405             qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
1406             return 0;
1407         }
1408 
1409         BOOL isSupportedFontType;
1410         DWRITE_FONT_FILE_TYPE fontFileType;
1411         DWRITE_FONT_FACE_TYPE fontFaceType;
1412         UINT32 numberOfFaces;
1413         fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
1414         if (!isSupportedFontType) {
1415             fontFile->Release();
1416             return 0;
1417         }
1418 
1419         IDWriteFontFace *directWriteFontFace = 0;
1420         hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
1421                                                                   1,
1422                                                                   &fontFile,
1423                                                                   0,
1424                                                                   DWRITE_FONT_SIMULATIONS_NONE,
1425                                                                   &directWriteFontFace);
1426         if (FAILED(hres)) {
1427             qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
1428             fontFile->Release();
1429             return 0;
1430         }
1431 
1432         fontFile->Release();
1433 
1434         fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
1435                                                        pixelSize,
1436                                                        fontEngineData);
1437 
1438         // Get font family from font data
1439         fontEngine->fontDef.family = font.familyName();
1440         fontEngine->fontDef.hintingPreference = hintingPreference;
1441 
1442         directWriteFontFace->Release();
1443     }
1444 #endif
1445 
1446     // Get style and weight info
1447     if (fontEngine != 0) {
1448         TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
1449         if (os2TableEntry != 0) {
1450             const OS2Table *os2Table =
1451                     reinterpret_cast<const OS2Table *>(fontData.constData()
1452                                                        + qFromBigEndian<quint32>(os2TableEntry->offset));
1453 
1454             bool italic = qFromBigEndian<quint16>(os2Table->selection)  & (1 << 0);
1455             bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
1456 
1457             if (italic)
1458                 fontEngine->fontDef.style = QFont::StyleItalic;
1459             else if (oblique)
1460                 fontEngine->fontDef.style = QFont::StyleOblique;
1461             else
1462                 fontEngine->fontDef.style = QFont::StyleNormal;
1463 
1464             fontEngine->fontDef.weight = QPlatformFontDatabase::weightFromInteger(qFromBigEndian<quint16>(os2Table->weightClass));
1465         }
1466     }
1467 
1468     qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
1469     return fontEngine;
1470 }
1471 
getTrueTypeFontOffsets(const uchar * fontData)1472 static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
1473 {
1474     QList<quint32> offsets;
1475     const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
1476     if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
1477         if (headerTag != MAKE_TAG(0, 1, 0, 0)
1478             && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
1479             && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
1480             && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
1481             return offsets;
1482         offsets << 0;
1483         return offsets;
1484     }
1485     const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
1486     for (uint i = 0; i < numFonts; ++i) {
1487         offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
1488     }
1489     return offsets;
1490 }
1491 
getFontTable(const uchar * fileBegin,const uchar * data,quint32 tag,const uchar ** table,quint32 * length)1492 static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
1493 {
1494     const quint16 numTables = qFromBigEndian<quint16>(data + 4);
1495     for (uint i = 0; i < numTables; ++i) {
1496         const quint32 offset = 12 + 16 * i;
1497         if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
1498             *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
1499             *length = qFromBigEndian<quint32>(data + offset + 12);
1500             return;
1501         }
1502     }
1503     *table = 0;
1504     *length = 0;
1505     return;
1506 }
1507 
getFamiliesAndSignatures(const QByteArray & fontData,QList<QFontNames> * families,QVector<FONTSIGNATURE> * signatures,QVector<QFontValues> * values)1508 static void getFamiliesAndSignatures(const QByteArray &fontData,
1509                                      QList<QFontNames> *families,
1510                                      QVector<FONTSIGNATURE> *signatures,
1511                                      QVector<QFontValues> *values)
1512 {
1513     const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
1514 
1515     QList<quint32> offsets = getTrueTypeFontOffsets(data);
1516     if (offsets.isEmpty())
1517         return;
1518 
1519     for (int i = 0; i < offsets.count(); ++i) {
1520         const uchar *font = data + offsets.at(i);
1521         const uchar *table;
1522         quint32 length;
1523         getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
1524         if (!table)
1525             continue;
1526         QFontNames names = qt_getCanonicalFontNames(table, length);
1527         if (names.name.isEmpty())
1528             continue;
1529 
1530         families->append(std::move(names));
1531 
1532         if (values || signatures)
1533             getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
1534 
1535         if (values) {
1536             QFontValues fontValues;
1537             if (table && length >= 64) {
1538                 // Read in some details about the font, offset calculated based on the specification
1539                 fontValues.weight = qFromBigEndian<quint16>(table + 4);
1540 
1541                 quint16 fsSelection = qFromBigEndian<quint16>(table + 62);
1542                 fontValues.isItalic = (fsSelection & 1) != 0;
1543                 fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0;
1544                 fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0;
1545             }
1546             values->append(std::move(fontValues));
1547         }
1548 
1549         if (signatures) {
1550             FONTSIGNATURE signature;
1551             if (table && length >= 86) {
1552                 // Offsets taken from OS/2 table in the TrueType spec
1553                 signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
1554                 signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
1555                 signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
1556                 signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
1557 
1558                 signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
1559                 signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
1560             } else {
1561                 memset(&signature, 0, sizeof(signature));
1562             }
1563             signatures->append(signature);
1564         }
1565     }
1566 }
1567 
addApplicationFont(const QByteArray & fontData,const QString & fileName)1568 QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
1569 {
1570     WinApplicationFont font;
1571     font.fileName = fileName;
1572     QVector<FONTSIGNATURE> signatures;
1573     QVector<QFontValues> fontValues;
1574     QList<QFontNames> families;
1575     QStringList familyNames;
1576 
1577     if (!fontData.isEmpty()) {
1578         getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues);
1579         if (families.isEmpty())
1580             return familyNames;
1581 
1582         DWORD dummy = 0;
1583         font.handle =
1584             AddFontMemResourceEx(const_cast<char *>(fontData.constData()),
1585                                  DWORD(fontData.size()), 0, &dummy);
1586         if (font.handle == 0)
1587             return QStringList();
1588 
1589         // Memory fonts won't show up in enumeration, so do add them the hard way.
1590         for (int j = 0; j < families.count(); ++j) {
1591             const auto &family = families.at(j);
1592             const QString &familyName = family.name;
1593             const QString &styleName = family.style;
1594             familyNames << familyName;
1595             HDC hdc = GetDC(0);
1596             LOGFONT lf;
1597             memset(&lf, 0, sizeof(LOGFONT));
1598             memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size()));
1599             lf.lfCharSet = DEFAULT_CHARSET;
1600             const QFontValues &values = fontValues.at(j);
1601             lf.lfWeight = values.weight;
1602             if (values.isItalic)
1603                 lf.lfItalic = TRUE;
1604             if (values.isOverstruck)
1605                 lf.lfStrikeOut = TRUE;
1606             if (values.isUnderlined)
1607                 lf.lfUnderline = TRUE;
1608             HFONT hfont = CreateFontIndirect(&lf);
1609             HGDIOBJ oldobj = SelectObject(hdc, hfont);
1610 
1611             TEXTMETRIC textMetrics;
1612             GetTextMetrics(hdc, &textMetrics);
1613 
1614             StoreFontPayload sfp(familyName, this);
1615             addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j),
1616                               TRUETYPE_FONTTYPE, &sfp);
1617 
1618             SelectObject(hdc, oldobj);
1619             DeleteObject(hfont);
1620             ReleaseDC(0, hdc);
1621         }
1622     } else {
1623         QFile f(fileName);
1624         if (!f.open(QIODevice::ReadOnly))
1625             return QStringList();
1626         QByteArray data = f.readAll();
1627         f.close();
1628 
1629         getFamiliesAndSignatures(data, &families, nullptr, nullptr);
1630         if (families.isEmpty())
1631             return QStringList();
1632 
1633         if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0)
1634             return QStringList();
1635 
1636         font.handle = 0;
1637 
1638         // Fonts based on files are added via populate, as they will show up in font enumeration.
1639         for (int j = 0; j < families.count(); ++j) {
1640             const QString familyName = families.at(j).name;
1641             familyNames << familyName;
1642             populateFamily(familyName);
1643         }
1644     }
1645 
1646     m_applicationFonts << font;
1647 
1648     return familyNames;
1649 }
1650 
removeApplicationFonts()1651 void QWindowsFontDatabase::removeApplicationFonts()
1652 {
1653     for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) {
1654         if (font.handle) {
1655             RemoveFontMemResourceEx(font.handle);
1656         } else {
1657             RemoveFontResourceExW(reinterpret_cast<LPCWSTR>(font.fileName.utf16()),
1658                                   FR_PRIVATE, nullptr);
1659         }
1660     }
1661     m_applicationFonts.clear();
1662     m_eudcFonts.clear();
1663 }
1664 
releaseHandle(void * handle)1665 void QWindowsFontDatabase::releaseHandle(void *handle)
1666 {
1667     const QChar *faceName = reinterpret_cast<const QChar *>(handle);
1668     delete[] faceName;
1669 }
1670 
fontDir() const1671 QString QWindowsFontDatabase::fontDir() const
1672 {
1673     const QString result = QPlatformFontDatabase::fontDir();
1674     qCDebug(lcQpaFonts) << __FUNCTION__ << result;
1675     return result;
1676 }
1677 
fontsAlwaysScalable() const1678 bool QWindowsFontDatabase::fontsAlwaysScalable() const
1679 {
1680     return false;
1681 }
1682 
derefUniqueFont(const QString & uniqueFont)1683 void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont)
1684 {
1685     if (m_uniqueFontData.contains(uniqueFont)) {
1686         if (!m_uniqueFontData[uniqueFont].refCount.deref()) {
1687             RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle);
1688             m_uniqueFontData.remove(uniqueFont);
1689         }
1690     }
1691 }
1692 
refUniqueFont(const QString & uniqueFont)1693 void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
1694 {
1695     if (m_uniqueFontData.contains(uniqueFont))
1696         m_uniqueFontData[uniqueFont].refCount.ref();
1697 }
1698 
1699 // ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont()
systemFont()1700 HFONT QWindowsFontDatabase::systemFont()
1701 {
1702     static const auto stock_sysfont =
1703         reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
1704     return stock_sysfont;
1705 }
1706 
1707 // Creation functions
1708 
1709 static const char *other_tryFonts[] = {
1710     "Arial",
1711     "MS UI Gothic",
1712     "Gulim",
1713     "SimSun",
1714     "PMingLiU",
1715     "Arial Unicode MS",
1716     0
1717 };
1718 
1719 static const char *jp_tryFonts [] = {
1720     "MS UI Gothic",
1721     "Arial",
1722     "Gulim",
1723     "SimSun",
1724     "PMingLiU",
1725     "Arial Unicode MS",
1726     0
1727 };
1728 
1729 static const char *ch_CN_tryFonts [] = {
1730     "SimSun",
1731     "Arial",
1732     "PMingLiU",
1733     "Gulim",
1734     "MS UI Gothic",
1735     "Arial Unicode MS",
1736     0
1737 };
1738 
1739 static const char *ch_TW_tryFonts [] = {
1740     "PMingLiU",
1741     "Arial",
1742     "SimSun",
1743     "Gulim",
1744     "MS UI Gothic",
1745     "Arial Unicode MS",
1746     0
1747 };
1748 
1749 static const char *kr_tryFonts[] = {
1750     "Gulim",
1751     "Arial",
1752     "PMingLiU",
1753     "SimSun",
1754     "MS UI Gothic",
1755     "Arial Unicode MS",
1756     0
1757 };
1758 
1759 static const char **tryFonts = 0;
1760 
fontDefToLOGFONT(const QFontDef & request,const QString & faceName)1761 LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName)
1762 {
1763     LOGFONT lf;
1764     memset(&lf, 0, sizeof(LOGFONT));
1765 
1766     lf.lfHeight = -qRound(request.pixelSize);
1767     lf.lfWidth                = 0;
1768     lf.lfEscapement        = 0;
1769     lf.lfOrientation        = 0;
1770     if (request.weight == 50)
1771         lf.lfWeight = FW_DONTCARE;
1772     else
1773         lf.lfWeight = (request.weight*900)/99;
1774     lf.lfItalic         = request.style != QFont::StyleNormal;
1775     lf.lfCharSet        = DEFAULT_CHARSET;
1776 
1777     int strat = OUT_DEFAULT_PRECIS;
1778     if (request.styleStrategy & QFont::PreferBitmap) {
1779         strat = OUT_RASTER_PRECIS;
1780     } else if (request.styleStrategy & QFont::PreferDevice) {
1781         strat = OUT_DEVICE_PRECIS;
1782     } else if (request.styleStrategy & QFont::PreferOutline) {
1783         strat = OUT_OUTLINE_PRECIS;
1784     } else if (request.styleStrategy & QFont::ForceOutline) {
1785         strat = OUT_TT_ONLY_PRECIS;
1786     }
1787 
1788     lf.lfOutPrecision   = strat;
1789 
1790     int qual = DEFAULT_QUALITY;
1791 
1792     if (request.styleStrategy & QFont::PreferMatch)
1793         qual = DRAFT_QUALITY;
1794     else if (request.styleStrategy & QFont::PreferQuality)
1795         qual = PROOF_QUALITY;
1796 
1797     if (request.styleStrategy & QFont::PreferAntialias) {
1798         qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
1799             ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
1800     } else if (request.styleStrategy & QFont::NoAntialias) {
1801         qual = NONANTIALIASED_QUALITY;
1802     } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && sharedFontData()->clearTypeEnabled) {
1803         qual = ANTIALIASED_QUALITY;
1804     }
1805 
1806     lf.lfQuality        = qual;
1807 
1808     lf.lfClipPrecision  = CLIP_DEFAULT_PRECIS;
1809 
1810     int hint = FF_DONTCARE;
1811     switch (request.styleHint) {
1812         case QFont::Helvetica:
1813             hint = FF_SWISS;
1814             break;
1815         case QFont::Times:
1816             hint = FF_ROMAN;
1817             break;
1818         case QFont::Courier:
1819             hint = FF_MODERN;
1820             break;
1821         case QFont::OldEnglish:
1822             hint = FF_DECORATIVE;
1823             break;
1824         case QFont::System:
1825             hint = FF_MODERN;
1826             break;
1827         default:
1828             break;
1829     }
1830 
1831     lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
1832 
1833     QString fam = faceName;
1834     if (fam.isEmpty())
1835         fam = request.families.size() > 0 ? request.families.at(0) : request.family;
1836     if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
1837         qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam));
1838         fam.truncate(LF_FACESIZE - 1);
1839     }
1840 
1841     if (fam.isEmpty())
1842         fam = QStringLiteral("MS Sans Serif");
1843 
1844     if (fam == QLatin1String("MS Sans Serif")
1845         && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
1846         fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
1847     }
1848     if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
1849         fam = QStringLiteral("Courier New");
1850 
1851     memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t));
1852 
1853     return lf;
1854 }
1855 
extraTryFontsForFamily(const QString & family)1856 QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family)
1857 {
1858     QStringList result;
1859     QFontDatabase db;
1860     if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) {
1861         if (!tryFonts) {
1862             LANGID lid = GetUserDefaultLangID();
1863             switch (lid&0xff) {
1864             case LANG_CHINESE: // Chinese
1865                 if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore
1866                     tryFonts = ch_CN_tryFonts;
1867                 else
1868                     tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau
1869                 break;
1870             case LANG_JAPANESE:
1871                 tryFonts = jp_tryFonts;
1872                 break;
1873             case LANG_KOREAN:
1874                 tryFonts = kr_tryFonts;
1875                 break;
1876             default:
1877                 tryFonts = other_tryFonts;
1878                 break;
1879             }
1880         }
1881         QFontDatabase db;
1882         const QStringList families = db.families();
1883         const char **tf = tryFonts;
1884         while (tf && *tf) {
1885             // QTBUG-31689, family might be an English alias for a localized font name.
1886             const QString family = QString::fromLatin1(*tf);
1887             if (families.contains(family) || db.hasFamily(family))
1888                 result << family;
1889             ++tf;
1890         }
1891     }
1892     result.append(QStringLiteral("Segoe UI Emoji"));
1893     result.append(QStringLiteral("Segoe UI Symbol"));
1894     return result;
1895 }
1896 
familyForStyleHint(QFont::StyleHint styleHint)1897 QString QWindowsFontDatabase::familyForStyleHint(QFont::StyleHint styleHint)
1898 {
1899     switch (styleHint) {
1900     case QFont::Times:
1901         return QStringLiteral("Times New Roman");
1902     case QFont::Courier:
1903         return QStringLiteral("Courier New");
1904     case QFont::Monospace:
1905         return QStringLiteral("Courier New");
1906     case QFont::Cursive:
1907         return QStringLiteral("Comic Sans MS");
1908     case QFont::Fantasy:
1909         return QStringLiteral("Impact");
1910     case QFont::Decorative:
1911         return QStringLiteral("Old English");
1912     case QFont::Helvetica:
1913         return QStringLiteral("Arial");
1914     case QFont::System:
1915     default:
1916         break;
1917     }
1918     return QStringLiteral("MS Shell Dlg 2");
1919 }
1920 
fallbacksForFamily(const QString & family,QFont::Style style,QFont::StyleHint styleHint,QChar::Script script) const1921 QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
1922 {
1923     QStringList result;
1924     result.append(QWindowsFontDatabase::familyForStyleHint(styleHint));
1925     result.append(m_eudcFonts);
1926     result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
1927     result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script));
1928 
1929     qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
1930         << script << result;
1931     return result;
1932 }
1933 
1934 
createEngine(const QFontDef & request,const QString & faceName,int dpi,const QSharedPointer<QWindowsFontEngineData> & data)1935 QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const QString &faceName,
1936                                                 int dpi,
1937                                                 const QSharedPointer<QWindowsFontEngineData> &data)
1938 {
1939     QFontEngine *fe = 0;
1940 
1941     LOGFONT lf = fontDefToLOGFONT(request, faceName);
1942     const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY;
1943 
1944     if (request.stretch != 100) {
1945         HFONT hfont = CreateFontIndirect(&lf);
1946         if (!hfont) {
1947             qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
1948             hfont = QWindowsFontDatabase::systemFont();
1949         }
1950 
1951         HGDIOBJ oldObj = SelectObject(data->hdc, hfont);
1952         TEXTMETRIC tm;
1953         if (!GetTextMetrics(data->hdc, &tm))
1954             qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
1955         else
1956             lf.lfWidth = tm.tmAveCharWidth * request.stretch / 100;
1957         SelectObject(data->hdc, oldObj);
1958 
1959         DeleteObject(hfont);
1960     }
1961 
1962 #if !defined(QT_NO_DIRECTWRITE)
1963     if (initDirectWrite(data.data())) {
1964         const QString fam = QString::fromWCharArray(lf.lfFaceName);
1965         const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
1966         if (nameSubstitute != fam) {
1967             const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
1968             memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t));
1969             lf.lfFaceName[nameSubstituteLength] = 0;
1970         }
1971 
1972         HFONT hfont = CreateFontIndirect(&lf);
1973         if (!hfont) {
1974             qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
1975         } else {
1976             HGDIOBJ oldFont = SelectObject(data->hdc, hfont);
1977 
1978             const QFont::HintingPreference hintingPreference =
1979                 static_cast<QFont::HintingPreference>(request.hintingPreference);
1980             bool useDw = useDirectWrite(hintingPreference, fam);
1981 
1982             IDWriteFontFace *directWriteFontFace = NULL;
1983             HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
1984             if (SUCCEEDED(hr)) {
1985                 bool isColorFont = false;
1986 #if defined(QT_USE_DIRECTWRITE2)
1987                 IDWriteFontFace2 *directWriteFontFace2 = nullptr;
1988                 if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
1989                                                                   reinterpret_cast<void **>(&directWriteFontFace2)))) {
1990                     if (directWriteFontFace2->IsColorFont())
1991                         isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0;
1992 
1993                     directWriteFontFace2->Release();
1994                 }
1995 #endif
1996                 useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont);
1997                 qCDebug(lcQpaFonts) << __FUNCTION__ << request.family << request.pointSize
1998                     << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont
1999                     << dpi << "dpi" << "useDirectWrite=" << useDw;
2000                 if (useDw) {
2001                     QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
2002                                                                                             request.pixelSize,
2003                                                                                             data);
2004 
2005                     wchar_t n[64];
2006                     GetTextFace(data->hdc, 64, n);
2007 
2008                     QFontDef fontDef = request;
2009                     fontDef.family = QString::fromWCharArray(n);
2010 
2011                     if (isColorFont)
2012                         fedw->glyphFormat = QFontEngine::Format_ARGB;
2013                     fedw->initFontInfo(fontDef, dpi);
2014                     fe = fedw;
2015                 }
2016                 directWriteFontFace->Release();
2017             } else if (useDw) {
2018                 const QString errorString = qt_error_string(int(hr));
2019                 qWarning().noquote().nospace() << "DirectWrite: CreateFontFaceFromHDC() failed ("
2020                     << errorString << ") for " << request << ' ' << lf << " dpi=" << dpi;
2021             }
2022 
2023             SelectObject(data->hdc, oldFont);
2024             DeleteObject(hfont);
2025         }
2026     }
2027 #endif // QT_NO_DIRECTWRITE
2028 
2029     if (!fe) {
2030         QWindowsFontEngine *few = new QWindowsFontEngine(request.family, lf, data);
2031         if (preferClearTypeAA)
2032             few->glyphFormat = QFontEngine::Format_A32;
2033         few->initFontInfo(request, dpi);
2034         fe = few;
2035     }
2036 
2037     return fe;
2038 }
2039 
systemDefaultFont()2040 QFont QWindowsFontDatabase::systemDefaultFont()
2041 {
2042 #if QT_VERSION >= 0x060000
2043     // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
2044     NONCLIENTMETRICS ncm;
2045     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
2046     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
2047     const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
2048 #else
2049     LOGFONT lf;
2050     GetObject(QWindowsFontDatabase::systemFont(), sizeof(lf), &lf);
2051     QFont systemFont =  QWindowsFontDatabase::LOGFONT_to_QFont(lf);
2052     // "MS Shell Dlg 2" is the correct system font >= Win2k
2053     if (systemFont.family() == QLatin1String("MS Shell Dlg"))
2054         systemFont.setFamily(QStringLiteral("MS Shell Dlg 2"));
2055     // Qt 5 by (Qt 4) legacy uses GetStockObject(DEFAULT_GUI_FONT) to
2056     // obtain the default GUI font (typically "MS Shell Dlg 2, 8pt"). This has been
2057     // long deprecated; the message font of the NONCLIENTMETRICS structure obtained by
2058     // SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see
2059     // QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger.
2060 #endif // Qt 5
2061     qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
2062     return systemFont;
2063 }
2064 
LOGFONT_to_QFont(const LOGFONT & logFont,int verticalDPI_In)2065 QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In)
2066 {
2067     if (verticalDPI_In <= 0)
2068         verticalDPI_In = defaultVerticalDPI();
2069     QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
2070     qFont.setItalic(logFont.lfItalic);
2071     if (logFont.lfWeight != FW_DONTCARE)
2072         qFont.setWeight(QPlatformFontDatabase::weightFromInteger(logFont.lfWeight));
2073     const qreal logFontHeight = qAbs(logFont.lfHeight);
2074     qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
2075     qFont.setUnderline(logFont.lfUnderline);
2076     qFont.setOverline(false);
2077     qFont.setStrikeOut(logFont.lfStrikeOut);
2078     return qFont;
2079 }
2080 
2081 static int s_defaultVerticalDPI = 96; // Native Pixels
2082 
defaultVerticalDPI()2083 int QWindowsFontDatabase::defaultVerticalDPI()
2084 {
2085     return s_defaultVerticalDPI;
2086 }
2087 
setDefaultVerticalDPI(int d)2088 void QWindowsFontDatabase::setDefaultVerticalDPI(int d)
2089 {
2090     s_defaultVerticalDPI = d;
2091 }
2092 
isPrivateFontFamily(const QString & family) const2093 bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const
2094 {
2095     return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family);
2096 }
2097 
2098 QT_END_NAMESPACE
2099