Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsfontdatabasebase.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <QtCore/QThreadStorage>
8#include <QtCore/QtEndian>
9
10#if QT_CONFIG(directwrite)
11# if QT_CONFIG(directwrite3)
12# include <dwrite_3.h>
13# else
14# include <dwrite_2.h>
15# endif
16# include <d2d1.h>
18#endif
19
21
22using namespace Qt::StringLiterals;
23
24// Helper classes for creating font engines directly from font data
25namespace {
26
27# pragma pack(1)
28
29 // Common structure for all formats of the "name" table
30 struct NameTable
31 {
34 quint16 stringOffset;
35 };
36
37 struct NameRecord
38 {
39 quint16 platformID;
40 quint16 encodingID;
41 quint16 languageID;
42 quint16 nameID;
45 };
46
47 struct OffsetSubTable
48 {
49 quint32 scalerType;
50 quint16 numTables;
51 quint16 searchRange;
52 quint16 entrySelector;
53 quint16 rangeShift;
54 };
55
56 struct TableDirectory : public QWindowsFontDatabaseBase::FontTable
57 {
58 quint32 identifier;
59 quint32 checkSum;
62 };
63
64 struct OS2Table
65 {
66 quint16 version;
67 qint16 avgCharWidth;
68 quint16 weightClass;
69 quint16 widthClass;
71 qint16 subscriptXSize;
72 qint16 subscriptYSize;
73 qint16 subscriptXOffset;
74 qint16 subscriptYOffset;
75 qint16 superscriptXSize;
76 qint16 superscriptYSize;
77 qint16 superscriptXOffset;
78 qint16 superscriptYOffset;
79 qint16 strikeOutSize;
80 qint16 strikeOutPosition;
81 qint16 familyClass;
82 quint8 panose[10];
83 quint32 unicodeRanges[4];
84 quint8 vendorID[4];
86 quint16 firstCharIndex;
87 quint16 lastCharIndex;
88 qint16 typoAscender;
89 qint16 typoDescender;
90 qint16 typoLineGap;
91 quint16 winAscent;
92 quint16 winDescent;
93 quint32 codepageRanges[2];
95 qint16 capHeight;
96 quint16 defaultChar;
97 quint16 breakChar;
98 quint16 maxContext;
99 };
100
101# pragma pack()
102
103} // Anonymous namespace
104
106{
107 Q_ASSERT(tagName.size() == 4);
108 quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData()));
109 const size_t fontDataSize = m_fontData.size();
110 if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable)))
111 return nullptr;
112
113 OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
114 TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
115
116 const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables);
117 if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount))
118 return nullptr;
119
120 TableDirectory *tableDirectoryEnd = tableDirectory + tableCount;
121 for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) {
122 if (entry->identifier == tagId)
123 return entry;
124 }
125
126 return nullptr;
127}
128
130{
132
133 TableDirectory *nameTableDirectoryEntry = static_cast<TableDirectory *>(directoryEntry);
134 if (nameTableDirectoryEntry == nullptr)
135 nameTableDirectoryEntry = static_cast<TableDirectory *>(tableDirectoryEntry("name"));
136
137 if (nameTableDirectoryEntry != nullptr) {
138 quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
139 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable)))
140 return QString();
141
142 NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + offset);
143 NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
144
145 quint16 nameTableCount = qFromBigEndian<quint16>(nameTable->count);
146 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount))
147 return QString();
148
149 for (int i = 0; i < nameTableCount; ++i, ++nameRecord) {
150 if (qFromBigEndian<quint16>(nameRecord->nameID) == 1
151 && qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows
152 && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English
153 quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
154 quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
155 quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
156
157 if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
158 return QString();
159
160 const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
161 + stringOffset
162 + nameOffset;
163
164 const quint16 *s = reinterpret_cast<const quint16 *>(ptr);
165 const quint16 *e = s + nameLength / sizeof(quint16);
166 while (s != e)
167 name += QChar( qFromBigEndian<quint16>(*s++));
168 break;
169 }
170 }
171 }
172
173 return name;
174}
175
177{
178 TableDirectory *os2TableEntry = static_cast<TableDirectory *>(tableDirectoryEntry("OS/2"));
179 if (os2TableEntry != nullptr) {
180 const OS2Table *os2Table =
181 reinterpret_cast<const OS2Table *>(m_fontData.constData()
182 + qFromBigEndian<quint32>(os2TableEntry->offset));
183
184 bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
185 bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
186
187 if (italic)
189 else if (oblique)
191 else
193
194 fontEngine->fontDef.weight = qFromBigEndian<quint16>(os2Table->weightClass);
195 }
196}
197
199{
200 TableDirectory *nameTableDirectoryEntry = static_cast<TableDirectory *>(tableDirectoryEntry("name"));
201 if (nameTableDirectoryEntry == nullptr)
202 return QString();
203
204 QString oldFamilyName = familyName(nameTableDirectoryEntry);
205
206 // Reserve size for name table header, five required name records and string
207 const int requiredRecordCount = 5;
208 quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
209
210 int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
211 int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16));
212
213 const QString regularString = QString::fromLatin1("Regular");
214 int regularStringSize = regularString.size() * int(sizeof(quint16));
215
216 // Align table size of table to 32 bits (pad with 0)
217 int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
218
219 QByteArray newNameTable(fullSize, char(0));
220
221 {
222 NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
223 nameTable->count = qbswap<quint16>(requiredRecordCount);
224 nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
225
226 NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
227 for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
228 nameRecord->nameID = qbswap<quint16>(nameIds[i]);
229 nameRecord->encodingID = qbswap<quint16>(1);
230 nameRecord->languageID = qbswap<quint16>(0x0409);
231 nameRecord->platformID = qbswap<quint16>(3);
232 nameRecord->length = qbswap<quint16>(newFamilyNameSize);
233
234 // Special case for sub-family
235 if (nameIds[i] == 4) {
236 nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
237 nameRecord->length = qbswap<quint16>(regularStringSize);
238 }
239 }
240
241 // nameRecord now points to string data
242 quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
243 for (QChar ch : newFamilyName)
244 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
245
246 for (QChar ch : regularString)
247 *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
248 }
249
250 quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
251 quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
252
253 quint32 checkSum = 0;
254 while (p < tableEnd)
255 checkSum += qFromBigEndian<quint32>(*(p++));
256
257 nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
258 nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
259 nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
260
261 m_fontData.append(newNameTable);
262
263 return oldFamilyName;
264}
265
266#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
267
268namespace {
269 class DirectWriteFontFileStream: public IDWriteFontFileStream
270 {
271 Q_DISABLE_COPY(DirectWriteFontFileStream)
272 public:
273 DirectWriteFontFileStream(const QByteArray &fontData)
274 : m_fontData(fontData)
275 , m_referenceCount(0)
276 {
277 }
278 virtual ~DirectWriteFontFileStream()
279 {
280 }
281
282 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) override;
283 ULONG STDMETHODCALLTYPE AddRef() override;
284 ULONG STDMETHODCALLTYPE Release() override;
285
286 HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
287 UINT64 fragmentSize, OUT void **fragmentContext) override;
288 void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext) override;
289 HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize) override;
290 HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime) override;
291
292 private:
293 QByteArray m_fontData;
294 ULONG m_referenceCount;
295 };
296
297 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
298 {
299 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
300 *object = this;
301 AddRef();
302 return S_OK;
303 } else {
304 *object = NULL;
305 return E_NOINTERFACE;
306 }
307 }
308
309 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
310 {
311 return InterlockedIncrement(&m_referenceCount);
312 }
313
314 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
315 {
316 ULONG newCount = InterlockedDecrement(&m_referenceCount);
317 if (newCount == 0)
318 delete this;
319 return newCount;
320 }
321
322 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
323 const void **fragmentStart,
324 UINT64 fileOffset,
325 UINT64 fragmentSize,
326 OUT void **fragmentContext)
327 {
328 *fragmentContext = NULL;
329 if (fileOffset + fragmentSize <= quint64(m_fontData.size())) {
330 *fragmentStart = m_fontData.data() + fileOffset;
331 return S_OK;
332 } else {
333 *fragmentStart = NULL;
334 return E_FAIL;
335 }
336 }
337
338 void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
339 {
340 }
341
342 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
343 {
344 *fileSize = m_fontData.size();
345 return S_OK;
346 }
347
348 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
349 {
350 *lastWriteTime = 0;
351 return E_NOTIMPL;
352 }
353
354 class DirectWriteFontFileLoader: public IDWriteFontFileLoader
355 {
356 public:
357 DirectWriteFontFileLoader() : m_referenceCount(0) {}
358 virtual ~DirectWriteFontFileLoader()
359 {
360 }
361
362 inline void addKey(const QByteArray &fontData)
363 {
364 if (!m_fontDatas.contains(fontData.data()))
365 m_fontDatas.insert(fontData.data(), fontData);
366 }
367
368 inline void removeKey(const void *key)
369 {
370 m_fontDatas.remove(key);
371 }
372
373 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) override;
374 ULONG STDMETHODCALLTYPE AddRef() override;
375 ULONG STDMETHODCALLTYPE Release() override;
376
377 HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
378 UINT32 fontFileReferenceKeySize,
379 OUT IDWriteFontFileStream **fontFileStream) override;
380
381 void clear()
382 {
383 m_fontDatas.clear();
384 }
385
386 private:
387 ULONG m_referenceCount;
388 QHash<const void *, QByteArray> m_fontDatas;
389 };
390
391 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
392 void **object)
393 {
394 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
395 *object = this;
396 AddRef();
397 return S_OK;
398 } else {
399 *object = NULL;
400 return E_NOINTERFACE;
401 }
402 }
403
404 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
405 {
406 return InterlockedIncrement(&m_referenceCount);
407 }
408
409 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
410 {
411 ULONG newCount = InterlockedDecrement(&m_referenceCount);
412 if (newCount == 0)
413 delete this;
414 return newCount;
415 }
416
417 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
418 void const *fontFileReferenceKey,
419 UINT32 fontFileReferenceKeySize,
420 IDWriteFontFileStream **fontFileStream)
421 {
422 Q_UNUSED(fontFileReferenceKeySize);
423
424 if (fontFileReferenceKeySize != sizeof(const void *)) {
425 qWarning("%s: Wrong key size", __FUNCTION__);
426 return E_FAIL;
427 }
428
429 const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
430 *fontFileStream = NULL;
431 auto it = m_fontDatas.constFind(key);
432 if (it == m_fontDatas.constEnd())
433 return E_FAIL;
434
435 QByteArray fontData = it.value();
436 DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
437 stream->AddRef();
438 *fontFileStream = stream;
439
440 return S_OK;
441 }
442
443} // Anonymous namespace
444
445class QCustomFontFileLoader
446{
447public:
448 QCustomFontFileLoader(IDWriteFactory *factory)
449 {
450 m_directWriteFactory = factory;
451
452 if (m_directWriteFactory) {
453 m_directWriteFactory->AddRef();
454
455 m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
456 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
457 }
458 }
459
460 ~QCustomFontFileLoader()
461 {
462 clear();
463
464 if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
465 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
466
467 if (m_directWriteFactory != nullptr)
468 m_directWriteFactory->Release();
469 }
470
471 void addKey(const QByteArray &fontData)
472 {
473 if (m_directWriteFontFileLoader != nullptr)
474 m_directWriteFontFileLoader->addKey(fontData);
475 }
476
477 void removeKey(const void *key)
478 {
479 if (m_directWriteFontFileLoader != nullptr)
480 m_directWriteFontFileLoader->removeKey(key);
481 }
482
483 IDWriteFontFileLoader *loader() const
484 {
485 return m_directWriteFontFileLoader;
486 }
487
488 void clear()
489 {
490 if (m_directWriteFontFileLoader != nullptr)
491 m_directWriteFontFileLoader->clear();
492 }
493
494private:
495 IDWriteFactory *m_directWriteFactory = nullptr;
496 DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
497};
498
499
500#endif // directwrite && direct2d
501
502
504{
505 if (hdc)
506 DeleteDC(hdc);
507
508#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
509 if (directWriteGdiInterop)
510 directWriteGdiInterop->Release();
511 if (directWriteFactory)
512 directWriteFactory->Release();
513#endif
514}
515
519
523
524typedef QSharedPointer<QWindowsFontEngineData> QWindowsFontEngineDataPtr;
525typedef QThreadStorage<QWindowsFontEngineDataPtr> FontEngineThreadLocalData;
526Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
527
529{
530 FontEngineThreadLocalData *data = fontEngineThreadLocalData();
531 if (!data->hasLocalData())
533
534 if (!init(data->localData()))
535 qCWarning(lcQpaFonts) << "Cannot initialize common font database data";
536
537 return data->localData();
538}
539
540bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
541{
542#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
543 if (!d->directWriteFactory) {
544 createDirectWriteFactory(&d->directWriteFactory);
545 if (!d->directWriteFactory)
546 return false;
547 }
548 if (!d->directWriteGdiInterop) {
549 const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
550 if (FAILED(hr)) {
551 qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__);
552 return false;
553 }
554 }
555#else
556 Q_UNUSED(d);
557#endif // directwrite && direct2d
558 return true;
559}
560
561#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
562void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
563{
564 *factory = nullptr;
565 IUnknown *result = nullptr;
566
567# if QT_CONFIG(directwrite3)
568 qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory6";
569 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
570
571 if (result == nullptr) {
572 qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory5";
573 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
574 }
575
576 if (result == nullptr) {
577 qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory3";
578 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
579 }
580# endif
581
582 if (result == nullptr) {
583 qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory2";
584 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
585 }
586
587 if (result == nullptr) {
588 qCDebug(lcQpaFonts) << "Trying to create plain IDWriteFactory";
589 if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
590 qErrnoWarning("DWriteCreateFactory failed");
591 return;
592 }
593 }
594
595 *factory = static_cast<IDWriteFactory *>(result);
596}
597#endif // directwrite && direct2d
598
600{
601 return 96;
602}
603
605{
606 LOGFONT lf;
607 memset(&lf, 0, sizeof(LOGFONT));
608
609 lf.lfHeight = -qRound(request.pixelSize);
610 lf.lfWidth = 0;
611 lf.lfEscapement = 0;
612 lf.lfOrientation = 0;
613 if (request.weight == QFont::Normal)
614 lf.lfWeight = FW_DONTCARE;
615 else
616 lf.lfWeight = request.weight;
617 lf.lfItalic = request.style != QFont::StyleNormal;
618 lf.lfCharSet = DEFAULT_CHARSET;
619
620 int strat = OUT_DEFAULT_PRECIS;
621 if (request.styleStrategy & QFont::PreferBitmap) {
622 strat = OUT_RASTER_PRECIS;
623 } else if (request.styleStrategy & QFont::PreferDevice) {
624 strat = OUT_DEVICE_PRECIS;
625 } else if (request.styleStrategy & QFont::PreferOutline) {
626 strat = OUT_OUTLINE_PRECIS;
627 } else if (request.styleStrategy & QFont::ForceOutline) {
628 strat = OUT_TT_ONLY_PRECIS;
629 }
630
631 lf.lfOutPrecision = strat;
632
633 int qual = DEFAULT_QUALITY;
634
635 if (request.styleStrategy & QFont::PreferMatch)
636 qual = DRAFT_QUALITY;
637 else if (request.styleStrategy & QFont::PreferQuality)
638 qual = PROOF_QUALITY;
639
640 if (request.styleStrategy & QFont::PreferAntialias) {
641 qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
642 ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
643 } else if (request.styleStrategy & QFont::NoAntialias) {
644 qual = NONANTIALIASED_QUALITY;
645 } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) {
646 qual = ANTIALIASED_QUALITY;
647 }
648
649 lf.lfQuality = qual;
650
651 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
652
653 int hint = FF_DONTCARE;
654 switch (request.styleHint) {
655 case QFont::Helvetica:
656 hint = FF_SWISS;
657 break;
658 case QFont::Times:
659 hint = FF_ROMAN;
660 break;
661 case QFont::Courier:
662 hint = FF_MODERN;
663 break;
665 hint = FF_DECORATIVE;
666 break;
667 case QFont::System:
668 hint = FF_MODERN;
669 break;
670 default:
671 break;
672 }
673
674 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
675
676 QString fam = faceName;
677 if (fam.isEmpty())
678 fam = request.families.first();
679 if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
680 qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam));
681 fam.truncate(LF_FACESIZE - 1);
682 }
683
684 memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t));
685
686 return lf;
687}
688
689QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In)
690{
691 if (verticalDPI_In <= 0)
692 verticalDPI_In = defaultVerticalDPI();
693 QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
694 qFont.setItalic(logFont.lfItalic);
695 if (logFont.lfWeight != FW_DONTCARE)
696 qFont.setWeight(QFont::Weight(logFont.lfWeight));
697 const qreal logFontHeight = qAbs(logFont.lfHeight);
698 qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
699 qFont.setUnderline(logFont.lfUnderline);
700 qFont.setOverline(false);
701 qFont.setStrikeOut(logFont.lfStrikeOut);
702 return qFont;
703}
704
705// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont()
707{
708 static const auto stock_sysfont =
709 reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
710 return stock_sysfont;
711}
712
714{
715 // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
716 NONCLIENTMETRICS ncm = {};
717 ncm.cbSize = sizeof(ncm);
718 SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
720 qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
721 return systemFont;
722}
723
725{
726#if QT_CONFIG(directwrite)
727 m_fontFileLoader.reset(nullptr);
728#endif
729}
730
731#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
732IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData)
733{
734 QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
735 Q_ASSERT(faces.size() <= 1);
736
737 return faces.isEmpty() ? nullptr : faces.first();
738}
739
740QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
741 bool queryVariations) const
742{
743 QList<IDWriteFontFace *> ret;
744 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
745 if (fontEngineData->directWriteFactory == nullptr) {
746 qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
747 return ret;
748 }
749
750 if (m_fontFileLoader == nullptr)
751 m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
752
753 m_fontFileLoader->addKey(fontData);
754
755 IDWriteFontFile *fontFile = nullptr;
756 const void *key = fontData.data();
757
758 HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
759 sizeof(void *),
760 m_fontFileLoader->loader(),
761 &fontFile);
762 if (FAILED(hres)) {
763 qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
764 return ret;
765 }
766
767 BOOL isSupportedFontType;
768 DWRITE_FONT_FILE_TYPE fontFileType;
769 DWRITE_FONT_FACE_TYPE fontFaceType;
770 UINT32 numberOfFaces;
771 fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
772 if (!isSupportedFontType) {
773 fontFile->Release();
774 return ret;
775 }
776
777#if QT_CONFIG(directwrite3)
778 IDWriteFactory5 *factory5 = nullptr;
779 if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
780 reinterpret_cast<void **>(&factory5)))) {
781
782 IDWriteFontSetBuilder1 *builder;
783 if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
784 if (SUCCEEDED(builder->AddFontFile(fontFile))) {
785 IDWriteFontSet *fontSet;
786 if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
787 int count = fontSet->GetFontCount();
788 qCDebug(lcQpaFonts) << "Found" << count << "variations in font file";
789 for (int i = 0; i < count; ++i) {
790 IDWriteFontFaceReference *ref;
791 if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
792 IDWriteFontFace3 *face;
793 if (SUCCEEDED(ref->CreateFontFace(&face))) {
794 ret.append(face);
795 }
796 ref->Release();
797 }
798 }
799 fontSet->Release();
800 }
801 }
802
803 builder->Release();
804 }
805
806 factory5->Release();
807 }
808#else
809 Q_UNUSED(queryVariations);
810#endif
811
812 // ### Currently no support for .ttc, but we could easily return a list here.
813 if (ret.isEmpty()) {
814 IDWriteFontFace *directWriteFontFace = nullptr;
815 hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
816 1,
817 &fontFile,
818 0,
819 DWRITE_FONT_SIMULATIONS_NONE,
820 &directWriteFontFace);
821 if (FAILED(hres)) {
822 qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
823 fontFile->Release();
824 return ret;
825 } else {
826 ret.append(directWriteFontFace);
827 }
828 }
829
830 fontFile->Release();
831
832 return ret;
833}
834#endif // directwrite && direct2d
835
837{
838 // This function was apparently not used before, and probably isn't now either,
839 // call the base implementation which just prints that it's not supported.
841}
842
844{
845 QFontEngine *fontEngine = nullptr;
846
847#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
848 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
849 if (fontEngineData->directWriteFactory == nullptr)
850 return nullptr;
851
852 IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
853 if (directWriteFontFace == nullptr)
854 return nullptr;
855
856 fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
857 pixelSize,
858 fontEngineData);
859
860 // Get font family from font data
862 font.updateFromOS2Table(fontEngine);
863 fontEngine->fontDef.families = QStringList(font.familyName());
864 fontEngine->fontDef.hintingPreference = hintingPreference;
865
866 directWriteFontFace->Release();
867#else // directwrite && direct2d
869 Q_UNUSED(pixelSize);
870 Q_UNUSED(hintingPreference);
871#endif
872
873 return fontEngine;
874}
875
877{
878 switch (styleHint) {
879 case QFont::Times:
880 return QStringLiteral("Times New Roman");
881 case QFont::Courier:
882 return QStringLiteral("Courier New");
883 case QFont::Monospace:
884 return QStringLiteral("Courier New");
885 case QFont::Cursive:
886 return QStringLiteral("Comic Sans MS");
887 case QFont::Fantasy:
888 return QStringLiteral("Impact");
890 return QStringLiteral("Old English");
891 case QFont::Helvetica:
892 return QStringLiteral("Arial");
893 case QFont::System:
894 default:
895 break;
896 }
897 return QStringLiteral("Tahoma");
898}
899
900// Creation functions
901
902static const char *other_tryFonts[] = {
903 "Arial",
904 "MS UI Gothic",
905 "Gulim",
906 "SimSun",
907 "PMingLiU",
908 "Arial Unicode MS",
909 0
910};
911
912static const char *jp_tryFonts [] = {
913 "Yu Gothic UI",
914 "MS UI Gothic",
915 "Arial",
916 "Gulim",
917 "SimSun",
918 "PMingLiU",
919 "Arial Unicode MS",
920 0
921};
922
923static const char *ch_CN_tryFonts [] = {
924 "SimSun",
925 "Arial",
926 "PMingLiU",
927 "Gulim",
928 "MS UI Gothic",
929 "Arial Unicode MS",
930 0
931};
932
933static const char *ch_TW_tryFonts [] = {
934 "PMingLiU",
935 "Arial",
936 "SimSun",
937 "Gulim",
938 "MS UI Gothic",
939 "Arial Unicode MS",
940 0
941};
942
943static const char *kr_tryFonts[] = {
944 "Gulim",
945 "Arial",
946 "PMingLiU",
947 "SimSun",
948 "MS UI Gothic",
949 "Arial Unicode MS",
950 0
951};
952
953static const char **tryFonts = nullptr;
954
956{
959 if (!tryFonts) {
960 LANGID lid = GetUserDefaultLangID();
961 switch (lid&0xff) {
962 case LANG_CHINESE: // Chinese
963 if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore
965 else
966 tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau
967 break;
968 case LANG_JAPANESE:
970 break;
971 case LANG_KOREAN:
973 break;
974 default:
976 break;
977 }
978 }
979 const QStringList families = QFontDatabase::families();
980 const char **tf = tryFonts;
981 while (tf && *tf) {
982 // QTBUG-31689, family might be an English alias for a localized font name.
983 const QString family = QString::fromLatin1(*tf);
984 if (families.contains(family) || QFontDatabase::hasFamily(family))
985 result << family;
986 ++tf;
987 }
988 }
989 result.append(QStringLiteral("Segoe UI Emoji"));
990 result.append(QStringLiteral("Segoe UI Symbol"));
991 return result;
992}
993
995{
996 QFontDef req = request;
997 const QString fam = request.families.front();
998 if (fam.isEmpty())
999 req.families[0] = QStringLiteral("MS Sans Serif");
1000
1001 if (fam == "MS Sans Serif"_L1) {
1002 int height = -qRound(request.pixelSize);
1003 // MS Sans Serif has bearing problems in italic, and does not scale
1004 if (request.style == QFont::StyleItalic || (height > 18 && height != 24))
1005 req.families[0] = QStringLiteral("Arial");
1006 }
1007
1008 if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier")
1009 req.families[0] = QStringLiteral("Courier New");
1010 return req;
1011}
1012
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
static QStringList families(WritingSystem writingSystem=Any)
Returns a sorted list of the available font families which support the writingSystem.
static bool hasFamily(const QString &family)
static QList< WritingSystem > writingSystems()
Returns a sorted list of the available writing systems.
QFontDef fontDef
\reentrant
Definition qfont.h:22
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
Definition qfont.h:25
@ Helvetica
Definition qfont.h:26
@ Monospace
Definition qfont.h:33
@ Times
Definition qfont.h:27
@ System
Definition qfont.h:30
@ Courier
Definition qfont.h:28
@ OldEnglish
Definition qfont.h:29
@ Decorative
Definition qfont.h:29
@ Cursive
Definition qfont.h:32
@ Fantasy
Definition qfont.h:34
HintingPreference
Definition qfont.h:55
@ PreferDevice
Definition qfont.h:41
@ NoSubpixelAntialias
Definition qfont.h:48
@ PreferQuality
Definition qfont.h:45
@ NoAntialias
Definition qfont.h:47
@ PreferBitmap
Definition qfont.h:40
@ ForceOutline
Definition qfont.h:43
@ PreferMatch
Definition qfont.h:44
@ PreferAntialias
Definition qfont.h:46
@ PreferOutline
Definition qfont.h:42
Weight
Qt uses a weighting scale from 1 to 1000 compatible with OpenType.
Definition qfont.h:63
@ Normal
Definition qfont.h:67
@ StyleItalic
Definition qfont.h:78
@ StyleNormal
Definition qfont.h:77
@ StyleOblique
Definition qfont.h:79
virtual QFontEngine * fontEngine(const QFontDef &fontDef, void *handle)
Returns the font engine that can be used to render the font described by the font definition,...
const_iterator constEnd() const noexcept
Definition qset.h:143
const_iterator constFind(const T &value) const
Definition qset.h:161
\inmodule QtCore
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
QString changeFamilyName(const QString &newFamilyName)
FontTable * tableDirectoryEntry(const QByteArray &tagName)
QString familyName(FontTable *nameTableDirectory=nullptr)
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
static QFont LOGFONT_to_QFont(const LOGFONT &lf, int verticalDPI=0)
static QStringList extraTryFontsForFamily(const QString &family)
void invalidate() override
This function is called whenever the font database is invalidated.
static QSharedPointer< QWindowsFontEngineData > data()
QFontDef sanitizeRequest(QFontDef request) const
static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName)
static QString familyForStyleHint(QFont::StyleHint styleHint)
Static constant data shared by the font engines.
Windows font engine using Direct Write.
b clear()
QSet< QString >::iterator it
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
#define Q_UNLIKELY(x)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
EGLStreamKHR stream
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
static void addKey(QString &str, const QString &theKey, QKeySequence::SequenceFormat format)
#define qCritical
Definition qlogging.h:167
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
static ControlElement< T > * ptr(QWidget *widget)
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLuint64 GLenum void * handle
GLuint64 key
GLint GLsizei GLsizei height
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum face
GLenum type
GLenum GLuint GLintptr offset
GLint ref
GLuint name
GLint GLsizei GLsizei GLenum format
GLenum GLsizeiptr const void * fontData
GLdouble s
[6]
Definition qopenglext.h:235
GLuint entry
GLint tagId
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define CLEARTYPE_QUALITY
Definition qt_windows.h:100
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
short qint16
Definition qtypes.h:47
unsigned short quint16
Definition qtypes.h:48
unsigned long long quint64
Definition qtypes.h:61
double qreal
Definition qtypes.h:187
unsigned char quint8
Definition qtypes.h:46
const char * OUT
long HRESULT
static const char * jp_tryFonts[]
static const char * other_tryFonts[]
QThreadStorage< QWindowsFontEngineDataPtr > FontEngineThreadLocalData
QSharedPointer< QWindowsFontEngineData > QWindowsFontEngineDataPtr
static const char * kr_tryFonts[]
static const char * ch_CN_tryFonts[]
static const char ** tryFonts
static const char * ch_TW_tryFonts[]
QObject::connect nullptr
QItemEditorFactory * factory
QItemSelection * selection
[0]
QNetworkRequest request(url)
uint hintingPreference
Definition qfont_p.h:67
uint style
Definition qfont_p.h:66
uint weight
Definition qfont_p.h:70
QStringList families
Definition qfont_p.h:54