Qt 6.x
The Qt SDK
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 void *key, const QByteArray &fontData)
363 {
364 Q_ASSERT(!m_fontDatas.contains(key));
365 m_fontDatas.insert(key, 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 private:
382 ULONG m_referenceCount;
384 };
385
386 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
387 void **object)
388 {
389 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
390 *object = this;
391 AddRef();
392 return S_OK;
393 } else {
394 *object = NULL;
395 return E_NOINTERFACE;
396 }
397 }
398
399 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
400 {
401 return InterlockedIncrement(&m_referenceCount);
402 }
403
404 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
405 {
406 ULONG newCount = InterlockedDecrement(&m_referenceCount);
407 if (newCount == 0)
408 delete this;
409 return newCount;
410 }
411
412 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
413 void const *fontFileReferenceKey,
414 UINT32 fontFileReferenceKeySize,
415 IDWriteFontFileStream **fontFileStream)
416 {
417 Q_UNUSED(fontFileReferenceKeySize);
418
419 if (fontFileReferenceKeySize != sizeof(const void *)) {
420 qWarning("%s: Wrong key size", __FUNCTION__);
421 return E_FAIL;
422 }
423
424 const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
425 *fontFileStream = NULL;
426 auto it = m_fontDatas.constFind(key);
427 if (it == m_fontDatas.constEnd())
428 return E_FAIL;
429
430 QByteArray fontData = it.value();
431 DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
432 stream->AddRef();
433 *fontFileStream = stream;
434
435 return S_OK;
436 }
437
438 class CustomFontFileLoader
439 {
440 public:
441 CustomFontFileLoader(IDWriteFactory *factory)
442 {
443 m_directWriteFactory = factory;
444
445 if (m_directWriteFactory) {
446 m_directWriteFactory->AddRef();
447
448 m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
449 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
450 }
451 }
452
453 ~CustomFontFileLoader()
454 {
455 if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
456 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
457
458 if (m_directWriteFactory != nullptr)
459 m_directWriteFactory->Release();
460 }
461
462 void addKey(const void *key, const QByteArray &fontData)
463 {
464 if (m_directWriteFontFileLoader != nullptr)
465 m_directWriteFontFileLoader->addKey(key, fontData);
466 }
467
468 void removeKey(const void *key)
469 {
470 if (m_directWriteFontFileLoader != nullptr)
471 m_directWriteFontFileLoader->removeKey(key);
472 }
473
474 IDWriteFontFileLoader *loader() const
475 {
476 return m_directWriteFontFileLoader;
477 }
478
479 private:
480 IDWriteFactory *m_directWriteFactory = nullptr;
481 DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
482 };
483} // Anonymous namespace
484
485#endif // directwrite && direct2d
486
487
489{
490 if (hdc)
491 DeleteDC(hdc);
492
493#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
494 if (directWriteGdiInterop)
495 directWriteGdiInterop->Release();
496 if (directWriteFactory)
497 directWriteFactory->Release();
498#endif
499}
500
502{
503}
504
506{
507}
508
511Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
512
514{
515 FontEngineThreadLocalData *data = fontEngineThreadLocalData();
516 if (!data->hasLocalData())
518
519 if (!init(data->localData()))
520 qCWarning(lcQpaFonts) << "Cannot initialize common font database data";
521
522 return data->localData();
523}
524
525bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
526{
527#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
528 if (!d->directWriteFactory) {
529 createDirectWriteFactory(&d->directWriteFactory);
530 if (!d->directWriteFactory)
531 return false;
532 }
533 if (!d->directWriteGdiInterop) {
534 const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
535 if (FAILED(hr)) {
536 qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__);
537 return false;
538 }
539 }
540#else
541 Q_UNUSED(d);
542#endif // directwrite && direct2d
543 return true;
544}
545
546#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
547void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
548{
549 *factory = nullptr;
550 IUnknown *result = nullptr;
551
552# if QT_CONFIG(directwrite3)
553 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
554# endif
555 if (result == nullptr)
556 DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
557
558 if (result == nullptr) {
559 if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
560 qErrnoWarning("DWriteCreateFactory failed");
561 return;
562 }
563 }
564
565 *factory = static_cast<IDWriteFactory *>(result);
566}
567#endif // directwrite && direct2d
568
570{
571 return 96;
572}
573
575{
576 LOGFONT lf;
577 memset(&lf, 0, sizeof(LOGFONT));
578
579 lf.lfHeight = -qRound(request.pixelSize);
580 lf.lfWidth = 0;
581 lf.lfEscapement = 0;
582 lf.lfOrientation = 0;
583 if (request.weight == QFont::Normal)
584 lf.lfWeight = FW_DONTCARE;
585 else
586 lf.lfWeight = request.weight;
587 lf.lfItalic = request.style != QFont::StyleNormal;
588 lf.lfCharSet = DEFAULT_CHARSET;
589
590 int strat = OUT_DEFAULT_PRECIS;
591 if (request.styleStrategy & QFont::PreferBitmap) {
592 strat = OUT_RASTER_PRECIS;
593 } else if (request.styleStrategy & QFont::PreferDevice) {
594 strat = OUT_DEVICE_PRECIS;
595 } else if (request.styleStrategy & QFont::PreferOutline) {
596 strat = OUT_OUTLINE_PRECIS;
597 } else if (request.styleStrategy & QFont::ForceOutline) {
598 strat = OUT_TT_ONLY_PRECIS;
599 }
600
601 lf.lfOutPrecision = strat;
602
603 int qual = DEFAULT_QUALITY;
604
605 if (request.styleStrategy & QFont::PreferMatch)
606 qual = DRAFT_QUALITY;
607 else if (request.styleStrategy & QFont::PreferQuality)
608 qual = PROOF_QUALITY;
609
610 if (request.styleStrategy & QFont::PreferAntialias) {
611 qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
612 ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
613 } else if (request.styleStrategy & QFont::NoAntialias) {
614 qual = NONANTIALIASED_QUALITY;
615 } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) {
616 qual = ANTIALIASED_QUALITY;
617 }
618
619 lf.lfQuality = qual;
620
621 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
622
623 int hint = FF_DONTCARE;
624 switch (request.styleHint) {
625 case QFont::Helvetica:
626 hint = FF_SWISS;
627 break;
628 case QFont::Times:
629 hint = FF_ROMAN;
630 break;
631 case QFont::Courier:
632 hint = FF_MODERN;
633 break;
635 hint = FF_DECORATIVE;
636 break;
637 case QFont::System:
638 hint = FF_MODERN;
639 break;
640 default:
641 break;
642 }
643
644 lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
645
646 QString fam = faceName;
647 if (fam.isEmpty())
648 fam = request.families.first();
649 if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
650 qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam));
651 fam.truncate(LF_FACESIZE - 1);
652 }
653
654 memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t));
655
656 return lf;
657}
658
659QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In)
660{
661 if (verticalDPI_In <= 0)
662 verticalDPI_In = defaultVerticalDPI();
663 QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
664 qFont.setItalic(logFont.lfItalic);
665 if (logFont.lfWeight != FW_DONTCARE)
666 qFont.setWeight(QFont::Weight(logFont.lfWeight));
667 const qreal logFontHeight = qAbs(logFont.lfHeight);
668 qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
669 qFont.setUnderline(logFont.lfUnderline);
670 qFont.setOverline(false);
671 qFont.setStrikeOut(logFont.lfStrikeOut);
672 return qFont;
673}
674
675// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont()
677{
678 static const auto stock_sysfont =
679 reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
680 return stock_sysfont;
681}
682
684{
685 // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
686 NONCLIENTMETRICS ncm = {};
687 ncm.cbSize = sizeof(ncm);
688 SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
690 qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
691 return systemFont;
692}
693
694#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
695IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const
696{
698 if (fontEngineData->directWriteFactory == nullptr) {
699 qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
700 return nullptr;
701 }
702
703 CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory);
704 fontFileLoader.addKey(this, fontData);
705
706 IDWriteFontFile *fontFile = nullptr;
707 const void *key = this;
708
709 HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
710 sizeof(void *),
711 fontFileLoader.loader(),
712 &fontFile);
713 if (FAILED(hres)) {
714 qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
715 return nullptr;
716 }
717
718 BOOL isSupportedFontType;
719 DWRITE_FONT_FILE_TYPE fontFileType;
720 DWRITE_FONT_FACE_TYPE fontFaceType;
721 UINT32 numberOfFaces;
722 fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
723 if (!isSupportedFontType) {
724 fontFile->Release();
725 return nullptr;
726 }
727
728 // ### Currently no support for .ttc, but we could easily return a list here.
729 IDWriteFontFace *directWriteFontFace = nullptr;
730 hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
731 1,
732 &fontFile,
733 0,
734 DWRITE_FONT_SIMULATIONS_NONE,
735 &directWriteFontFace);
736 if (FAILED(hres)) {
737 qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
738 fontFile->Release();
739 return nullptr;
740 }
741
742 fontFile->Release();
743 return directWriteFontFace;
744}
745#endif // directwrite && direct2d
746
748{
749 // This function was apparently not used before, and probably isn't now either,
750 // call the base implementation which just prints that it's not supported.
752}
753
755{
756 QFontEngine *fontEngine = nullptr;
757
758#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
760 if (fontEngineData->directWriteFactory == nullptr)
761 return nullptr;
762
763 IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData);
764 fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
765 pixelSize,
766 fontEngineData);
767
768 // Get font family from font data
770 font.updateFromOS2Table(fontEngine);
771 fontEngine->fontDef.families = QStringList(font.familyName());
772 fontEngine->fontDef.hintingPreference = hintingPreference;
773
774 directWriteFontFace->Release();
775#else // directwrite && direct2d
777 Q_UNUSED(pixelSize);
778 Q_UNUSED(hintingPreference);
779#endif
780
781 return fontEngine;
782}
783
785{
786 switch (styleHint) {
787 case QFont::Times:
788 return QStringLiteral("Times New Roman");
789 case QFont::Courier:
790 return QStringLiteral("Courier New");
791 case QFont::Monospace:
792 return QStringLiteral("Courier New");
793 case QFont::Cursive:
794 return QStringLiteral("Comic Sans MS");
795 case QFont::Fantasy:
796 return QStringLiteral("Impact");
798 return QStringLiteral("Old English");
799 case QFont::Helvetica:
800 return QStringLiteral("Arial");
801 case QFont::System:
802 default:
803 break;
804 }
805 return QStringLiteral("Tahoma");
806}
807
808// Creation functions
809
810static const char *other_tryFonts[] = {
811 "Arial",
812 "MS UI Gothic",
813 "Gulim",
814 "SimSun",
815 "PMingLiU",
816 "Arial Unicode MS",
817 0
818};
819
820static const char *jp_tryFonts [] = {
821 "Yu Gothic UI",
822 "MS UI Gothic",
823 "Arial",
824 "Gulim",
825 "SimSun",
826 "PMingLiU",
827 "Arial Unicode MS",
828 0
829};
830
831static const char *ch_CN_tryFonts [] = {
832 "SimSun",
833 "Arial",
834 "PMingLiU",
835 "Gulim",
836 "MS UI Gothic",
837 "Arial Unicode MS",
838 0
839};
840
841static const char *ch_TW_tryFonts [] = {
842 "PMingLiU",
843 "Arial",
844 "SimSun",
845 "Gulim",
846 "MS UI Gothic",
847 "Arial Unicode MS",
848 0
849};
850
851static const char *kr_tryFonts[] = {
852 "Gulim",
853 "Arial",
854 "PMingLiU",
855 "SimSun",
856 "MS UI Gothic",
857 "Arial Unicode MS",
858 0
859};
860
861static const char **tryFonts = nullptr;
862
864{
867 if (!tryFonts) {
868 LANGID lid = GetUserDefaultLangID();
869 switch (lid&0xff) {
870 case LANG_CHINESE: // Chinese
871 if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore
873 else
874 tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau
875 break;
876 case LANG_JAPANESE:
878 break;
879 case LANG_KOREAN:
881 break;
882 default:
884 break;
885 }
886 }
887 const QStringList families = QFontDatabase::families();
888 const char **tf = tryFonts;
889 while (tf && *tf) {
890 // QTBUG-31689, family might be an English alias for a localized font name.
891 const QString family = QString::fromLatin1(*tf);
892 if (families.contains(family) || QFontDatabase::hasFamily(family))
893 result << family;
894 ++tf;
895 }
896 }
897 result.append(QStringLiteral("Segoe UI Emoji"));
898 result.append(QStringLiteral("Segoe UI Symbol"));
899 return result;
900}
901
903{
904 QFontDef req = request;
905 const QString fam = request.families.front();
906 if (fam.isEmpty())
907 req.families[0] = QStringLiteral("MS Sans Serif");
908
909 if (fam == "MS Sans Serif"_L1) {
910 int height = -qRound(request.pixelSize);
911 // MS Sans Serif has bearing problems in italic, and does not scale
912 if (request.style == QFont::StyleItalic || (height > 18 && height != 24))
913 req.families[0] = QStringLiteral("Arial");
914 }
915
916 if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier")
917 req.families[0] = QStringLiteral("Courier New");
918 return req;
919}
920
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
\inmodule QtCore
Definition qchar.h:48
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:20
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
Definition qfont.h:23
@ Helvetica
Definition qfont.h:24
@ Monospace
Definition qfont.h:31
@ Times
Definition qfont.h:25
@ System
Definition qfont.h:28
@ Courier
Definition qfont.h:26
@ OldEnglish
Definition qfont.h:27
@ Decorative
Definition qfont.h:27
@ Cursive
Definition qfont.h:30
@ Fantasy
Definition qfont.h:32
void setOverline(bool)
If enable is true, sets overline on; otherwise sets overline off.
Definition qfont.cpp:1273
void setStrikeOut(bool)
If enable is true, sets strikeout on; otherwise sets strikeout off.
Definition qfont.cpp:1300
void setItalic(bool b)
Sets the style() of the font to QFont::StyleItalic if enable is true; otherwise the style is set to Q...
Definition qfont.h:320
void setUnderline(bool)
If enable is true, sets underline on; otherwise sets underline off.
Definition qfont.cpp:1247
HintingPreference
Definition qfont.h:52
@ PreferDevice
Definition qfont.h:39
@ NoSubpixelAntialias
Definition qfont.h:46
@ PreferQuality
Definition qfont.h:43
@ NoAntialias
Definition qfont.h:45
@ PreferBitmap
Definition qfont.h:38
@ ForceOutline
Definition qfont.h:41
@ PreferMatch
Definition qfont.h:42
@ PreferAntialias
Definition qfont.h:44
@ PreferOutline
Definition qfont.h:40
void setPointSizeF(qreal)
Sets the point size to pointSize.
Definition qfont.cpp:995
Weight
Qt uses a weighting scale from 1 to 1000 compatible with OpenType.
Definition qfont.h:60
@ Normal
Definition qfont.h:64
void setWeight(Weight weight)
Sets the weight of the font to weight, using the scale defined by \l QFont::Weight enumeration.
Definition qfont.cpp:1190
@ StyleItalic
Definition qfont.h:75
@ StyleNormal
Definition qfont.h:74
@ StyleOblique
Definition qfont.h:76
\inmodule QtCore
Definition qhash.h:818
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:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6159
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1164
QString & append(QChar c)
Definition qstring.cpp:3227
\inmodule QtCore
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)
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.
double e
QSet< QString >::iterator it
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
#define Q_UNLIKELY(x)
EGLStreamKHR stream
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
static void addKey(QString &str, const QString &theKey, QKeySequence::SequenceFormat format)
#define qCritical
Definition qlogging.h:163
#define qWarning
Definition qlogging.h:162
#define qCWarning(category,...)
#define qCDebug(category,...)
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
GLenum type
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLuint name
GLint GLsizei GLsizei GLenum format
GLenum GLsizeiptr const void * fontData
GLuint entry
GLint tagId
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1391
#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:45
short qint16
Definition qtypes.h:42
unsigned short quint16
Definition qtypes.h:43
unsigned long long quint64
Definition qtypes.h:56
double qreal
Definition qtypes.h:92
unsigned char quint8
Definition qtypes.h:41
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[]
QItemEditorFactory * factory
QItemSelection * selection
[0]
QNetworkRequest request(url)
uint hintingPreference
Definition qfont_p.h:66
uint style
Definition qfont_p.h:65
uint weight
Definition qfont_p.h:69
QStringList families
Definition qfont_p.h:54