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