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