1// Copyright (C) 2016 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
4#include "qplatformfontdatabase.h"
5#include <QtGui/private/qfontengine_p.h>
6#include <QtGui/private/qfontdatabase_p.h>
7#include <QtGui/QGuiApplication>
8#include <QtGui/QScreen>
9#include <qpa/qplatformscreen.h>
10#include <QtCore/QLibraryInfo>
11#include <QtCore/QDir>
12#include <QtCore/QMetaEnum>
13#include <QtCore/qendian.h>
14
15#include <algorithm>
16#include <iterator>
17
18QT_BEGIN_NAMESPACE
19
20using namespace Qt::StringLiterals;
21
22Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
23
24void qt_registerFont(const QString &familyname, const QString &stylename,
25 const QString &foundryname, int weight,
26 QFont::Style style, int stretch, bool antialiased,
27 bool scalable, int pixelSize, bool fixedPitch,
28 const QSupportedWritingSystems &writingSystems, void *hanlde);
29
30void qt_registerFontFamily(const QString &familyName);
31void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
32bool qt_isFontFamilyPopulated(const QString &familyName);
33
34/*!
35 Registers a font with the given set of attributes describing the font's
36 foundry, family name, style and stretch information, pixel size, and
37 supported writing systems. Additional information about whether the font
38 can be scaled and antialiased can also be provided.
39
40 The foundry name and font family are described by \a foundryName and
41 \a familyName. The font weight (light, normal, bold, etc.), style (normal,
42 oblique, italic) and stretch information (condensed, expanded, unstretched,
43 etc.) are specified by \a weight, \a style and \a stretch.
44
45 Some fonts can be antialiased and scaled; \a scalable and \a antialiased
46 can be set to true for fonts with these attributes. The intended pixel
47 size of non-scalable fonts is specified by \a pixelSize; this value will be
48 ignored for scalable fonts.
49
50 The writing systems supported by the font are specified by the
51 \a writingSystems argument.
52
53 \sa registerFontFamily()
54*/
55void QPlatformFontDatabase::registerFont(const QString &familyname, const QString &stylename,
56 const QString &foundryname, QFont::Weight weight,
57 QFont::Style style, QFont::Stretch stretch, bool antialiased,
58 bool scalable, int pixelSize, bool fixedPitch,
59 const QSupportedWritingSystems &writingSystems, void *usrPtr)
60{
61 if (scalable)
62 pixelSize = 0;
63
64 qt_registerFont(familyname, stylename, foundryname, weight, style,
65 stretch, antialiased, scalable, pixelSize,
66 fixedPitch, writingSystems, hanlde: usrPtr);
67}
68
69/*!
70 Registers a font family with the font database. The font will be
71 lazily populated by a callback to populateFamily() when the font
72 database determines that the family needs population.
73
74 \sa populateFamily(), registerFont()
75*/
76void QPlatformFontDatabase::registerFontFamily(const QString &familyName)
77{
78 qt_registerFontFamily(familyName);
79}
80
81class QWritingSystemsPrivate
82{
83public:
84 QWritingSystemsPrivate()
85 : ref(1)
86 , list(QFontDatabase::WritingSystemsCount, false)
87 {
88 }
89
90 QWritingSystemsPrivate(const QWritingSystemsPrivate *other)
91 : ref(1)
92 , list(other->list)
93 {
94 }
95
96 QAtomicInt ref;
97 QList<bool> list;
98};
99
100/*!
101 Constructs a new object to handle supported writing systems.
102*/
103QSupportedWritingSystems::QSupportedWritingSystems()
104{
105 d = new QWritingSystemsPrivate;
106}
107
108/*!
109 Constructs a copy of the \a other writing systems object.
110*/
111QSupportedWritingSystems::QSupportedWritingSystems(const QSupportedWritingSystems &other)
112{
113 d = other.d;
114 d->ref.ref();
115}
116
117/*!
118 Constructs a copy of the \a other writing systems object.
119*/
120QSupportedWritingSystems &QSupportedWritingSystems::operator=(const QSupportedWritingSystems &other)
121{
122 if (d != other.d) {
123 other.d->ref.ref();
124 if (!d->ref.deref())
125 delete d;
126 d = other.d;
127 }
128 return *this;
129}
130
131bool operator==(const QSupportedWritingSystems &lhs, const QSupportedWritingSystems &rhs)
132{
133 return !(lhs != rhs);
134}
135
136bool operator!=(const QSupportedWritingSystems &lhs, const QSupportedWritingSystems &rhs)
137{
138 if (lhs.d == rhs.d)
139 return false;
140
141 Q_ASSERT(lhs.d->list.size() == rhs.d->list.size());
142 Q_ASSERT(lhs.d->list.size() == QFontDatabase::WritingSystemsCount);
143 for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
144 if (lhs.d->list.at(i) != rhs.d->list.at(i))
145 return true;
146 }
147
148 return false;
149}
150
151#ifndef QT_NO_DEBUG_STREAM
152QDebug operator<<(QDebug debug, const QSupportedWritingSystems &sws)
153{
154 const QMetaObject *mo = &QFontDatabase::staticMetaObject;
155 QMetaEnum me = mo->enumerator(index: mo->indexOfEnumerator(name: "WritingSystem"));
156
157 QDebugStateSaver saver(debug);
158 debug.nospace() << "QSupportedWritingSystems(";
159 int i = sws.d->list.indexOf(t: true);
160 while (i > 0) {
161 debug << me.valueToKey(value: i);
162 i = sws.d->list.indexOf(t: true, from: i + 1);
163 if (i > 0)
164 debug << ", ";
165 }
166 debug << ")";
167 return debug;
168}
169#endif
170
171/*!
172 Destroys the supported writing systems object.
173*/
174QSupportedWritingSystems::~QSupportedWritingSystems()
175{
176 if (!d->ref.deref())
177 delete d;
178}
179
180/*!
181 \internal
182*/
183void QSupportedWritingSystems::detach()
184{
185 if (d->ref.loadRelaxed() != 1) {
186 QWritingSystemsPrivate *newd = new QWritingSystemsPrivate(d);
187 if (!d->ref.deref())
188 delete d;
189 d = newd;
190 }
191}
192
193/*!
194 Sets or clears support for the specified \a writingSystem based on the
195 value given by \a support.
196*/
197void QSupportedWritingSystems::setSupported(QFontDatabase::WritingSystem writingSystem, bool support)
198{
199 detach();
200 d->list[writingSystem] = support;
201}
202
203/*!
204 Returns \c true if the writing system specified by \a writingSystem is
205 supported; otherwise returns \c false.
206*/
207bool QSupportedWritingSystems::supported(QFontDatabase::WritingSystem writingSystem) const
208{
209 return d->list.at(i: writingSystem);
210}
211
212/*!
213 \class QSupportedWritingSystems
214 \brief The QSupportedWritingSystems class is used when registering fonts with the internal Qt
215 fontdatabase.
216 \ingroup painting
217 \inmodule QtGui
218
219 Its to provide an easy to use interface for indicating what writing systems a specific font
220 supports.
221
222*/
223
224/*!
225 \internal
226 */
227QPlatformFontDatabase::~QPlatformFontDatabase()
228{
229}
230
231/*!
232 This function is called once at startup by Qt's internal font database.
233 Reimplement this function in a subclass for a convenient place to initialize
234 the internal font database.
235
236 You may lazily populate the database by calling registerFontFamily() instead
237 of registerFont(), in which case you'll get a callback to populateFamily()
238 when the required family needs population. You then call registerFont() to
239 finish population of the family.
240
241 The default implementation does nothing.
242*/
243void QPlatformFontDatabase::populateFontDatabase()
244{
245}
246
247/*!
248 This function is called whenever a lazily populated family, populated
249 through registerFontFamily(), needs full population.
250
251 You are expected to fully populate the family by calling registerFont()
252 for each font that matches the family name.
253*/
254void QPlatformFontDatabase::populateFamily(const QString &familyName)
255{
256 Q_UNUSED(familyName);
257}
258
259/*!
260 This function is called whenever the font database is invalidated.
261
262 Reimplement this function to clear any internal data structures that
263 will need to be rebuilt at the next call to populateFontDatabase().
264*/
265void QPlatformFontDatabase::invalidate()
266{
267}
268
269/*!
270 Returns a multi font engine in the specified \a script to encapsulate \a fontEngine with the
271 option to fall back to the fonts given by \a fallbacks if \a fontEngine does not support
272 a certain character.
273*/
274QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script)
275{
276 return new QFontEngineMulti(fontEngine, script);
277}
278
279/*!
280 Returns the font engine that can be used to render the font described by
281 the font definition, \a fontDef, in the specified \a script.
282
283 This function is called by QFontDatabase both for system fonts provided
284 by the platform font database, as well as for application fonts added by
285 the application developer.
286
287 The handle is the QPlatformFontDatabase specific handle passed when
288 registering the font family via QPlatformFontDatabase::registerFont.
289
290 The function is called for both fonts added via a filename as well
291 as fonts added from QByteArray data. Subclasses will need to handle
292 both cases via its platform specific handle.
293*/
294QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
295{
296 Q_UNUSED(fontDef);
297 Q_UNUSED(handle);
298 qWarning(msg: "This plugin does not support loading system fonts.");
299 return nullptr;
300}
301
302/*!
303 Returns the font engine that will be used to back a QRawFont,
304 based on the given \fontData, \a pixelSize, and \a hintingPreference.
305
306 This function is called by QRawFont, and does not play a part in
307 the normal operations of QFontDatabase.
308*/
309QFontEngine *QPlatformFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
310 QFont::HintingPreference hintingPreference)
311{
312 Q_UNUSED(fontData);
313 Q_UNUSED(pixelSize);
314 Q_UNUSED(hintingPreference);
315 qWarning(msg: "This plugin does not support font engines created directly from font data");
316 return nullptr;
317}
318
319/*!
320 Adds an application font described by the font contained supplied \a fontData
321 or using the font contained in the file referenced by \a fileName. Returns
322 a list of family names, or an empty list if the font could not be added.
323
324 If \a applicationFont is non-null, its \c properties list should be filled
325 with information from the loaded fonts. This is exposed through FontLoader in
326 Qt Quick where it is needed for disambiguating fonts in the same family. When
327 the function exits, the \a applicationFont should contain an entry of properties
328 per font in the file, or it should be empty if no font was loaded.
329
330 \note The default implementation of this function does not add an application
331 font. Subclasses should reimplement this function to perform the necessary
332 loading and registration of fonts.
333*/
334QStringList QPlatformFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
335{
336 Q_UNUSED(fontData);
337 Q_UNUSED(fileName);
338 Q_UNUSED(applicationFont);
339
340 if (applicationFont != nullptr)
341 applicationFont->properties.clear();
342
343 qWarning(msg: "This plugin does not support application fonts");
344
345 return QStringList();
346}
347
348/*!
349 Releases the specified font \a handle.
350*/
351void QPlatformFontDatabase::releaseHandle(void *handle)
352{
353 QByteArray *fileDataPtr = static_cast<QByteArray *>(handle);
354 delete fileDataPtr;
355}
356
357/*!
358 Returns the directory containing the fonts used by the database.
359*/
360QString QPlatformFontDatabase::fontDir() const
361{
362 QString fontpath = QString::fromLocal8Bit(ba: qgetenv(varName: "QT_QPA_FONTDIR"));
363 if (fontpath.isEmpty())
364 fontpath = QLibraryInfo::path(p: QLibraryInfo::LibrariesPath) + "/fonts"_L1;
365
366 return fontpath;
367}
368
369/*!
370 Returns true if the font family is private. For any given family name,
371 the result is platform dependent.
372*/
373bool QPlatformFontDatabase::isPrivateFontFamily(const QString &family) const
374{
375 Q_UNUSED(family);
376 return false;
377}
378
379/*!
380 Returns the default system font.
381
382 \sa QGuiApplication::font()
383 \since 5.0
384*/
385
386QFont QPlatformFontDatabase::defaultFont() const
387{
388 return QFont("Helvetica"_L1);
389}
390
391
392QString qt_resolveFontFamilyAlias(const QString &alias);
393
394/*!
395 Resolve alias to actual font family names.
396
397 \since 5.0
398 */
399QString QPlatformFontDatabase::resolveFontFamilyAlias(const QString &family) const
400{
401 return qt_resolveFontFamilyAlias(alias: family);
402}
403
404/*!
405 Return true if all fonts are considered scalable when using this font database.
406 Defaults to false.
407
408 \since 5.0
409 */
410
411bool QPlatformFontDatabase::fontsAlwaysScalable() const
412{
413 return false;
414}
415
416/*!
417 Return list of standard font sizes when using this font database.
418
419 \since 5.0
420 */
421
422 QList<int> QPlatformFontDatabase::standardSizes() const
423{
424 QList<int> ret;
425 static const quint8 standard[] =
426 { 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 };
427 static const int num_standards = int(sizeof standard / sizeof *standard);
428 ret.reserve(asize: num_standards);
429 std::copy(first: standard, last: standard + num_standards, result: std::back_inserter(x&: ret));
430 return ret;
431}
432
433// see the Unicode subset bitfields in the MSDN docs
434static const quint8 requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
435 { 127, 127 }, // Any
436 { 0, 127 }, // Latin
437 { 7, 127 }, // Greek
438 { 9, 127 }, // Cyrillic
439 { 10, 127 }, // Armenian
440 { 11, 127 }, // Hebrew
441 { 13, 127 }, // Arabic
442 { 71, 127 }, // Syriac
443 { 72, 127 }, // Thaana
444 { 15, 127 }, // Devanagari
445 { 16, 127 }, // Bengali
446 { 17, 127 }, // Gurmukhi
447 { 18, 127 }, // Gujarati
448 { 19, 127 }, // Oriya
449 { 20, 127 }, // Tamil
450 { 21, 127 }, // Telugu
451 { 22, 127 }, // Kannada
452 { 23, 127 }, // Malayalam
453 { 73, 127 }, // Sinhala
454 { 24, 127 }, // Thai
455 { 25, 127 }, // Lao
456 { 70, 127 }, // Tibetan
457 { 74, 127 }, // Myanmar
458 { 26, 127 }, // Georgian
459 { 80, 127 }, // Khmer
460 { 126, 127 }, // SimplifiedChinese
461 { 126, 127 }, // TraditionalChinese
462 { 126, 127 }, // Japanese
463 { 56, 127 }, // Korean
464 { 0, 127 }, // Vietnamese (same as latin1)
465 { 126, 127 }, // Other
466 { 78, 127 }, // Ogham
467 { 79, 127 }, // Runic
468 { 14, 127 }, // Nko
469};
470
471enum CsbBits {
472 Latin1CsbBit = 0,
473 CentralEuropeCsbBit = 1,
474 TurkishCsbBit = 4,
475 BalticCsbBit = 7,
476 CyrillicCsbBit = 2,
477 GreekCsbBit = 3,
478 HebrewCsbBit = 5,
479 ArabicCsbBit = 6,
480 VietnameseCsbBit = 8,
481 SimplifiedChineseCsbBit = 18,
482 TraditionalChineseCsbBit = 20,
483 ThaiCsbBit = 16,
484 JapaneseCsbBit = 17,
485 KoreanCsbBit = 19,
486 KoreanJohabCsbBit = 21,
487 SymbolCsbBit = 31
488};
489
490/*!
491 Helper function that determines the writing system support based on the contents of the OS/2 table
492 in the font.
493
494 \since 6.0
495*/
496QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromOS2Table(const char *os2Table, size_t length)
497{
498 if (length >= 86) {
499 quint32 unicodeRange[4] = {
500 qFromBigEndian<quint32>(src: os2Table + 42),
501 qFromBigEndian<quint32>(src: os2Table + 46),
502 qFromBigEndian<quint32>(src: os2Table + 50),
503 qFromBigEndian<quint32>(src: os2Table + 54)
504 };
505 quint32 codePageRange[2] = {
506 qFromBigEndian<quint32>(src: os2Table + 78),
507 qFromBigEndian<quint32>(src: os2Table + 82)
508 };
509
510 return writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
511 }
512
513 return QSupportedWritingSystems();
514}
515
516/*!
517 Helper function that determines the writing systems support by a given
518 \a unicodeRange and \a codePageRange.
519
520 \since 5.1
521*/
522QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
523{
524 QSupportedWritingSystems writingSystems;
525
526 bool hasScript = false;
527 for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
528 int bit = requiredUnicodeBits[i][0];
529 int index = bit/32;
530 int flag = 1 << (bit&31);
531 if (bit != 126 && (unicodeRange[index] & flag)) {
532 bit = requiredUnicodeBits[i][1];
533 index = bit/32;
534
535 flag = 1 << (bit&31);
536 if (bit == 127 || (unicodeRange[index] & flag)) {
537 writingSystems.setSupported(writingSystem: QFontDatabase::WritingSystem(i));
538 hasScript = true;
539 // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i);
540 }
541 }
542 }
543 if (codePageRange[0] & ((1 << Latin1CsbBit) | (1 << CentralEuropeCsbBit) | (1 << TurkishCsbBit) | (1 << BalticCsbBit))) {
544 writingSystems.setSupported(writingSystem: QFontDatabase::Latin);
545 hasScript = true;
546 //qDebug("font %s supports Latin", familyName.latin1());
547 }
548 if (codePageRange[0] & (1 << CyrillicCsbBit)) {
549 writingSystems.setSupported(writingSystem: QFontDatabase::Cyrillic);
550 hasScript = true;
551 //qDebug("font %s supports Cyrillic", familyName.latin1());
552 }
553 if (codePageRange[0] & (1 << GreekCsbBit)) {
554 writingSystems.setSupported(writingSystem: QFontDatabase::Greek);
555 hasScript = true;
556 //qDebug("font %s supports Greek", familyName.latin1());
557 }
558 if (codePageRange[0] & (1 << HebrewCsbBit)) {
559 writingSystems.setSupported(writingSystem: QFontDatabase::Hebrew);
560 hasScript = true;
561 //qDebug("font %s supports Hebrew", familyName.latin1());
562 }
563 if (codePageRange[0] & (1 << ArabicCsbBit)) {
564 writingSystems.setSupported(writingSystem: QFontDatabase::Arabic);
565 hasScript = true;
566 //qDebug("font %s supports Arabic", familyName.latin1());
567 }
568 if (codePageRange[0] & (1 << ThaiCsbBit)) {
569 writingSystems.setSupported(writingSystem: QFontDatabase::Thai);
570 hasScript = true;
571 //qDebug("font %s supports Thai", familyName.latin1());
572 }
573 if (codePageRange[0] & (1 << VietnameseCsbBit)) {
574 writingSystems.setSupported(writingSystem: QFontDatabase::Vietnamese);
575 hasScript = true;
576 //qDebug("font %s supports Vietnamese", familyName.latin1());
577 }
578 if (codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
579 writingSystems.setSupported(writingSystem: QFontDatabase::SimplifiedChinese);
580 hasScript = true;
581 //qDebug("font %s supports Simplified Chinese", familyName.latin1());
582 }
583 if (codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
584 writingSystems.setSupported(writingSystem: QFontDatabase::TraditionalChinese);
585 hasScript = true;
586 //qDebug("font %s supports Traditional Chinese", familyName.latin1());
587 }
588 if (codePageRange[0] & (1 << JapaneseCsbBit)) {
589 writingSystems.setSupported(writingSystem: QFontDatabase::Japanese);
590 hasScript = true;
591 //qDebug("font %s supports Japanese", familyName.latin1());
592 }
593 if (codePageRange[0] & ((1 << KoreanCsbBit) | (1 << KoreanJohabCsbBit))) {
594 writingSystems.setSupported(writingSystem: QFontDatabase::Korean);
595 hasScript = true;
596 //qDebug("font %s supports Korean", familyName.latin1());
597 }
598 if (codePageRange[0] & (1U << SymbolCsbBit)) {
599 writingSystems = QSupportedWritingSystems();
600 hasScript = false;
601 }
602
603 if (!hasScript)
604 writingSystems.setSupported(writingSystem: QFontDatabase::Symbol);
605
606 return writingSystems;
607}
608
609/*!
610 Helper function that register the \a alias for the \a familyName.
611
612 \since 5.2
613*/
614
615void QPlatformFontDatabase::registerAliasToFontFamily(const QString &familyName, const QString &alias)
616{
617 qt_registerAliasToFontFamily(familyName, alias);
618}
619
620/*!
621 Requests that the platform font database should be repopulated.
622
623 This will result in invalidating the entire font database.
624
625 The next time the font database is accessed it will be repopulated
626 via a call to QPlatformFontDatabase::populate().
627
628 Application fonts will not be removed, and will be automatically
629 populated when the font database is repopulated.
630
631 \since 6.4
632*/
633void QPlatformFontDatabase::repopulateFontDatabase()
634{
635 QFontDatabasePrivate::instance()->invalidate();
636}
637
638/*!
639 Helper function that returns true if the font family has already been registered and populated.
640
641 \since 5.14
642*/
643bool QPlatformFontDatabase::isFamilyPopulated(const QString &familyName)
644{
645 return qt_isFontFamilyPopulated(familyName);
646}
647
648/*!
649 \class QPlatformFontDatabase
650 \since 5.0
651 \internal
652 \preliminary
653 \ingroup qpa
654 \ingroup painting
655
656 \brief The QPlatformFontDatabase class makes it possible to customize how fonts
657 are discovered and how they are rendered
658
659 QPlatformFontDatabase is the superclass which is intended to let platform implementations use
660 native font handling.
661
662 Qt has its internal font database which it uses to discover available fonts on the
663 user's system. To be able to populate this database subclass this class, and
664 reimplement populateFontDatabase().
665
666 Use the function registerFont() to populate the internal font database.
667
668 Sometimes a specified font does not have the required glyphs; in such a case, the
669 fallbackForFamily() function is called automatically to find alternative font
670 families that can supply alternatives to the missing glyphs.
671
672 \sa QSupportedWritingSystems
673*/
674QT_END_NAMESPACE
675

source code of qtbase/src/gui/text/qplatformfontdatabase.cpp