Coverage Report

Created: 2025-07-16 07:53

/src/qtbase/src/gui/text/qfontdatabase.cpp
Line
Count
Source (jump to first uncovered line)
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 "qfontdatabase.h"
5
#include "qfontdatabase_p.h"
6
#include "qloggingcategory.h"
7
#include "qalgorithms.h"
8
#include "qguiapplication.h"
9
#include "qvarlengtharray.h" // here or earlier - workaround for VC++6
10
#include "qthread.h"
11
#include "qmutex.h"
12
#include "qfile.h"
13
#include "qfileinfo.h"
14
#include "qfontengine_p.h"
15
#include <qpa/qplatformintegration.h>
16
17
#include <QtGui/private/qguiapplication_p.h>
18
#include <qpa/qplatformfontdatabase.h>
19
#include <qpa/qplatformtheme.h>
20
21
#include <QtCore/qcache.h>
22
#include <QtCore/qmath.h>
23
24
#include <stdlib.h>
25
#include <algorithm>
26
27
#include <qtgui_tracepoints_p.h>
28
29
#ifdef Q_OS_WIN
30
#include <QtGui/private/qwindowsfontdatabasebase_p.h>
31
#endif
32
33
QT_BEGIN_NAMESPACE
34
35
using namespace Qt::StringLiterals;
36
37
Q_LOGGING_CATEGORY(lcFontDb, "qt.text.font.db")
38
Q_LOGGING_CATEGORY(lcFontMatch, "qt.text.font.match")
39
40
0
#define SMOOTH_SCALABLE 0xffff
41
42
#if defined(QT_BUILD_INTERNAL)
43
bool qt_enable_test_font = false;
44
45
Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value)
46
{
47
    qt_enable_test_font = value;
48
}
49
#endif
50
51
Q_TRACE_POINT(qtgui, QFontDatabase_loadEngine, const QString &families, int pointSize);
52
Q_TRACE_POINT(qtgui, QFontDatabasePrivate_addAppFont, const QString &fileName);
53
Q_TRACE_POINT(qtgui, QFontDatabase_addApplicationFont, const QString &fileName);
54
Q_TRACE_POINT(qtgui, QFontDatabase_load, const QString &family, int pointSize);
55
56
static int getFontWeight(const QString &weightString)
57
0
{
58
0
    QString s = weightString.toLower();
59
60
    // Order here is important. We want to match the common cases first, but we
61
    // must also take care to acknowledge the cost of our tests.
62
    //
63
    // As a result, we test in two orders; the order of commonness, and the
64
    // order of "expense".
65
    //
66
    // A simple string test is the cheapest, so let's do that first.
67
    // Test in decreasing order of commonness
68
0
    if (s == "normal"_L1 || s == "regular"_L1)
69
0
        return QFont::Normal;
70
0
    if (s == "bold"_L1)
71
0
        return QFont::Bold;
72
0
    if (s == "semibold"_L1 || s == "semi bold"_L1 || s == "demibold"_L1 || s == "demi bold"_L1)
73
0
        return QFont::DemiBold;
74
0
    if (s == "medium"_L1)
75
0
        return QFont::Medium;
76
0
    if (s == "black"_L1)
77
0
        return QFont::Black;
78
0
    if (s == "light"_L1)
79
0
        return QFont::Light;
80
0
    if (s == "thin"_L1)
81
0
        return QFont::Thin;
82
0
    const QStringView s2 = QStringView{s}.mid(2);
83
0
    if (s.startsWith("ex"_L1) || s.startsWith("ul"_L1)) {
84
0
            if (s2 == "tralight"_L1 || s == "tra light"_L1)
85
0
                return QFont::ExtraLight;
86
0
            if (s2 == "trabold"_L1 || s2 == "tra bold"_L1)
87
0
                return QFont::ExtraBold;
88
0
    }
89
90
    // Next up, let's see if contains() matches: slightly more expensive, but
91
    // still fast enough.
92
0
    if (s.contains("bold"_L1)) {
93
0
        if (s.contains("demi"_L1))
94
0
            return QFont::DemiBold;
95
0
        return QFont::Bold;
96
0
    }
97
0
    if (s.contains("thin"_L1))
98
0
        return QFont::Thin;
99
0
    if (s.contains("light"_L1))
100
0
        return QFont::Light;
101
0
    if (s.contains("black"_L1))
102
0
        return QFont::Black;
103
104
    // Now, we perform string translations & comparisons with those.
105
    // These are (very) slow compared to simple string ops, so we do these last.
106
    // As using translated values for such things is not very common, this should
107
    // not be too bad.
108
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight"), Qt::CaseInsensitive) == 0)
109
0
        return QFont::Normal;
110
0
    const QString translatedBold = QCoreApplication::translate("QFontDatabase", "Bold").toLower();
111
0
    if (s == translatedBold)
112
0
        return QFont::Bold;
113
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Demi Bold"), Qt::CaseInsensitive) == 0)
114
0
        return QFont::DemiBold;
115
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Medium", "The Medium font weight"), Qt::CaseInsensitive) == 0)
116
0
        return QFont::Medium;
117
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
118
0
        return QFont::Black;
119
0
    const QString translatedLight = QCoreApplication::translate("QFontDatabase", "Light").toLower();
120
0
    if (s == translatedLight)
121
0
        return QFont::Light;
122
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Thin"), Qt::CaseInsensitive) == 0)
123
0
        return QFont::Thin;
124
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Extra Light"), Qt::CaseInsensitive) == 0)
125
0
        return QFont::ExtraLight;
126
0
    if (s.compare(QCoreApplication::translate("QFontDatabase", "Extra Bold"), Qt::CaseInsensitive) == 0)
127
0
        return QFont::ExtraBold;
128
129
    // And now the contains() checks for the translated strings.
130
    //: The word for "Extra" as in "Extra Bold, Extra Thin" used as a pattern for string searches
131
0
    const QString translatedExtra = QCoreApplication::translate("QFontDatabase", "Extra").toLower();
132
0
    if (s.contains(translatedBold)) {
133
        //: The word for "Demi" as in "Demi Bold" used as a pattern for string searches
134
0
        QString translatedDemi = QCoreApplication::translate("QFontDatabase", "Demi").toLower();
135
0
        if (s .contains(translatedDemi))
136
0
            return QFont::DemiBold;
137
0
        if (s.contains(translatedExtra))
138
0
            return QFont::ExtraBold;
139
0
        return QFont::Bold;
140
0
    }
141
142
0
    if (s.contains(translatedLight)) {
143
0
        if (s.contains(translatedExtra))
144
0
            return QFont::ExtraLight;
145
0
        return QFont::Light;
146
0
    }
147
0
    return QFont::Normal;
148
0
}
149
150
151
QtFontStyle::Key::Key(const QString &styleString)
152
0
    : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0)
153
0
{
154
0
    weight = getFontWeight(styleString);
155
156
0
    if (!styleString.isEmpty()) {
157
        // First the straightforward no-translation checks, these are fast.
158
0
        if (styleString.contains("Italic"_L1))
159
0
            style = QFont::StyleItalic;
160
0
        else if (styleString.contains("Oblique"_L1))
161
0
            style = QFont::StyleOblique;
162
163
        // Then the translation checks. These aren't as fast.
164
0
        else if (styleString.contains(QCoreApplication::translate("QFontDatabase", "Italic")))
165
0
            style = QFont::StyleItalic;
166
0
        else if (styleString.contains(QCoreApplication::translate("QFontDatabase", "Oblique")))
167
0
            style = QFont::StyleOblique;
168
0
    }
169
0
}
170
171
QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add)
172
0
{
173
0
    for (int i = 0; i < count; i++) {
174
0
        if (pixelSizes[i].pixelSize == size)
175
0
            return pixelSizes + i;
176
0
    }
177
0
    if (!add)
178
0
        return nullptr;
179
180
0
    if (!pixelSizes) {
181
        // Most style have only one font size, we avoid waisting memory
182
0
        QtFontSize *newPixelSizes = (QtFontSize *)malloc(sizeof(QtFontSize));
183
0
        Q_CHECK_PTR(newPixelSizes);
184
0
        pixelSizes = newPixelSizes;
185
0
    } else if (!(count % 8) || count == 1) {
186
0
        QtFontSize *newPixelSizes = (QtFontSize *)
187
0
                     realloc(pixelSizes,
188
0
                              (((count+8) >> 3) << 3) * sizeof(QtFontSize));
189
0
        Q_CHECK_PTR(newPixelSizes);
190
0
        pixelSizes = newPixelSizes;
191
0
    }
192
0
    pixelSizes[count].pixelSize = size;
193
0
    pixelSizes[count].handle = nullptr;
194
0
    return pixelSizes + (count++);
195
0
}
196
197
QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, const QString &styleName, StyleRetrievalFlags flags)
198
0
{
199
0
    int pos = 0;
200
0
    for (; pos < count; pos++) {
201
0
        bool hasStyleName = !styleName.isEmpty() && !styles[pos]->styleName.isEmpty();
202
0
        bool hasStyleNameMatch = styles[pos]->styleName == styleName;
203
0
        bool hasKeyMatch = styles[pos]->key == key;
204
205
        // If MatchAllProperties are set, then both the key and style name have to match, otherwise
206
        // we consider it a different font. If it is not set, then we prefer matches on the style
207
        // name if there is one. If no style name is part of the request (or the font does not
208
        // have one) we match on the key.
209
0
        if (flags & MatchAllProperties) {
210
0
            if (hasStyleNameMatch && hasKeyMatch)
211
0
                return styles[pos];
212
0
        } else if (hasStyleName) {
213
0
            if (hasStyleNameMatch)
214
0
                return styles[pos];
215
0
        } else if (hasKeyMatch) {
216
0
            return styles[pos];
217
0
        }
218
0
    }
219
0
    if (!(flags & AddWhenMissing))
220
0
        return nullptr;
221
222
//     qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos);
223
0
    if (!(count % 8)) {
224
0
        QtFontStyle **newStyles = (QtFontStyle **)
225
0
                 realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *));
226
0
        Q_CHECK_PTR(newStyles);
227
0
        styles = newStyles;
228
0
    }
229
230
0
    QtFontStyle *style = new QtFontStyle(key);
231
0
    style->styleName = styleName;
232
0
    styles[pos] = style;
233
0
    count++;
234
0
    return styles[pos];
235
0
}
236
237
QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create)
238
0
{
239
0
    if (f.isNull() && count == 1)
240
0
        return foundries[0];
241
242
0
    for (int i = 0; i < count; i++) {
243
0
        if (foundries[i]->name.compare(f, Qt::CaseInsensitive) == 0)
244
0
            return foundries[i];
245
0
    }
246
0
    if (!create)
247
0
        return nullptr;
248
249
0
    if (!(count % 8)) {
250
0
        QtFontFoundry **newFoundries = (QtFontFoundry **)
251
0
                    realloc(foundries,
252
0
                             (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *));
253
0
        Q_CHECK_PTR(newFoundries);
254
0
        foundries = newFoundries;
255
0
    }
256
257
0
    foundries[count] = new QtFontFoundry(f);
258
0
    return foundries[count++];
259
0
}
260
261
static inline bool equalsCaseInsensitive(const QString &a, const QString &b)
262
0
{
263
0
    return a.size() == b.size() && a.compare(b, Qt::CaseInsensitive) == 0;
264
0
}
265
266
bool QtFontFamily::matchesFamilyName(const QString &familyName) const
267
0
{
268
0
    return equalsCaseInsensitive(name, familyName) || aliases.contains(familyName, Qt::CaseInsensitive);
269
0
}
270
271
bool QtFontFamily::ensurePopulated()
272
0
{
273
0
    if (populated)
274
0
        return true;
275
276
0
    QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamily(name);
277
0
    return populated;
278
0
}
279
280
void QFontDatabasePrivate::clearFamilies()
281
0
{
282
0
    while (count--)
283
0
        delete families[count];
284
0
    ::free(families);
285
0
    families = nullptr;
286
0
    count = 0;
287
288
0
    for (auto &font : applicationFonts)
289
0
        font.properties.clear(); // Unpopulate
290
291
0
    populated = false;
292
    // don't clear the memory fonts!
293
0
}
294
295
void QFontDatabasePrivate::invalidate()
296
0
{
297
0
    qCDebug(lcFontDb) << "Invalidating font database";
298
299
0
    QFontCache::instance()->clear();
300
301
0
    fallbacksCache.clear();
302
0
    clearFamilies();
303
0
    QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate();
304
0
    emit qGuiApp->fontDatabaseChanged();
305
0
}
306
307
QtFontFamily *QFontDatabasePrivate::family(const QString &f, FamilyRequestFlags flags)
308
0
{
309
0
    QtFontFamily *fam = nullptr;
310
311
0
    int low = 0;
312
0
    int high = count;
313
0
    int pos = count / 2;
314
0
    int res = 1;
315
0
    if (count) {
316
0
        while ((res = families[pos]->name.compare(f, Qt::CaseInsensitive)) && pos != low) {
317
0
            if (res > 0)
318
0
                high = pos;
319
0
            else
320
0
                low = pos;
321
0
            pos = (high + low) / 2;
322
0
        }
323
0
        if (!res)
324
0
            fam = families[pos];
325
0
    }
326
327
0
    if (!fam && (flags & EnsureCreated)) {
328
0
        if (res < 0)
329
0
            pos++;
330
331
        // qDebug() << "adding family " << f.toLatin1() << " at " << pos << " total=" << count;
332
0
        if (!(count % 8)) {
333
0
            QtFontFamily **newFamilies = (QtFontFamily **)
334
0
                       realloc(families,
335
0
                                (((count+8) >> 3) << 3) * sizeof(QtFontFamily *));
336
0
            Q_CHECK_PTR(newFamilies);
337
0
            families = newFamilies;
338
0
        }
339
340
0
        QtFontFamily *family = new QtFontFamily(f);
341
0
        memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *));
342
0
        families[pos] = family;
343
0
        count++;
344
345
0
        fam = families[pos];
346
0
    }
347
348
0
    if (fam && (flags & EnsurePopulated)) {
349
0
        if (!fam->ensurePopulated())
350
0
            return nullptr;
351
0
    }
352
353
0
    return fam;
354
0
}
355
356
357
358
static const int scriptForWritingSystem[] = {
359
    QChar::Script_Common, // Any
360
    QChar::Script_Latin, // Latin
361
    QChar::Script_Greek, // Greek
362
    QChar::Script_Cyrillic, // Cyrillic
363
    QChar::Script_Armenian, // Armenian
364
    QChar::Script_Hebrew, // Hebrew
365
    QChar::Script_Arabic, // Arabic
366
    QChar::Script_Syriac, // Syriac
367
    QChar::Script_Thaana, // Thaana
368
    QChar::Script_Devanagari, // Devanagari
369
    QChar::Script_Bengali, // Bengali
370
    QChar::Script_Gurmukhi, // Gurmukhi
371
    QChar::Script_Gujarati, // Gujarati
372
    QChar::Script_Oriya, // Oriya
373
    QChar::Script_Tamil, // Tamil
374
    QChar::Script_Telugu, // Telugu
375
    QChar::Script_Kannada, // Kannada
376
    QChar::Script_Malayalam, // Malayalam
377
    QChar::Script_Sinhala, // Sinhala
378
    QChar::Script_Thai, // Thai
379
    QChar::Script_Lao, // Lao
380
    QChar::Script_Tibetan, // Tibetan
381
    QChar::Script_Myanmar, // Myanmar
382
    QChar::Script_Georgian, // Georgian
383
    QChar::Script_Khmer, // Khmer
384
    QChar::Script_Han, // SimplifiedChinese
385
    QChar::Script_Han, // TraditionalChinese
386
    QChar::Script_Han, // Japanese
387
    QChar::Script_Hangul, // Korean
388
    QChar::Script_Latin, // Vietnamese
389
    QChar::Script_Common, // Symbol
390
    QChar::Script_Ogham,  // Ogham
391
    QChar::Script_Runic, // Runic
392
    QChar::Script_Nko // Nko
393
};
394
395
static_assert(sizeof(scriptForWritingSystem) / sizeof(scriptForWritingSystem[0]) == QFontDatabase::WritingSystemsCount);
396
397
Q_GUI_EXPORT int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem)
398
0
{
399
0
    return scriptForWritingSystem[writingSystem];
400
0
}
401
402
403
/*!
404
    \internal
405
406
    Tests if the given family \a family supports writing system \a writingSystem,
407
    including the special case for Han script mapping to several subsequent writing systems
408
*/
409
static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSystem)
410
0
{
411
0
    Q_ASSERT(family != nullptr);
412
0
    Q_ASSERT(writingSystem != QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount);
413
414
0
    size_t ws = writingSystem;
415
0
    do {
416
0
        if ((family->writingSystems[ws] & QtFontFamily::Supported) != 0)
417
0
            return true;
418
0
    } while (writingSystem >= QFontDatabase::SimplifiedChinese && writingSystem <= QFontDatabase::Japanese && ++ws <= QFontDatabase::Japanese);
419
420
0
    return false;
421
0
}
422
423
Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script)
424
0
{
425
0
    if (script >= QChar::ScriptCount)
426
0
        return QFontDatabase::Any;
427
0
    return QFontDatabase::WritingSystem(std::find(scriptForWritingSystem,
428
0
                                                  scriptForWritingSystem + QFontDatabase::WritingSystemsCount,
429
0
                                                  script) - scriptForWritingSystem);
430
0
}
431
432
/*!
433
  \internal
434
435
  This makes sense of the font family name:
436
437
  if the family name contains a '[' and a ']', then we take the text
438
  between the square brackets as the foundry, and the text before the
439
  square brackets as the family (ie. "Arial [Monotype]")
440
*/
441
static void parseFontName(const QString &name, QString &foundry, QString &family)
442
0
{
443
0
    int i = name.indexOf(u'[');
444
0
    int li = name.lastIndexOf(u']');
445
0
    if (i >= 0 && li >= 0 && i < li) {
446
0
        foundry = name.mid(i + 1, li - i - 1);
447
0
        if (i > 0 && name[i - 1] == u' ')
448
0
            i--;
449
0
        family = name.left(i);
450
0
    } else {
451
0
        foundry.clear();
452
0
        family = name;
453
0
    }
454
455
    // capitalize the family/foundry names
456
0
    bool space = true;
457
0
    QChar *s = family.data();
458
0
    int len = family.size();
459
0
    while(len--) {
460
0
        if (space) *s = s->toUpper();
461
0
        space = s->isSpace();
462
0
        ++s;
463
0
    }
464
465
0
    space = true;
466
0
    s = foundry.data();
467
0
    len = foundry.size();
468
0
    while(len--) {
469
0
        if (space) *s = s->toUpper();
470
0
        space = s->isSpace();
471
0
        ++s;
472
0
    }
473
0
}
474
475
476
struct QtFontDesc
477
{
478
0
    inline QtFontDesc() : family(nullptr), foundry(nullptr), style(nullptr), size(nullptr) {}
479
    QtFontFamily *family;
480
    QtFontFoundry *foundry;
481
    QtFontStyle *style;
482
    QtFontSize *size;
483
};
484
485
static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi)
486
0
{
487
0
    QString family;
488
0
    family = desc.family->name;
489
0
    if (! desc.foundry->name.isEmpty() && desc.family->count > 1)
490
0
        family += " ["_L1 + desc.foundry->name + u']';
491
0
    fontDef->families = QStringList(family);
492
493
0
    if (desc.style->smoothScalable
494
0
        || QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable()
495
0
        || (desc.style->bitmapScalable && (request.styleStrategy & QFont::PreferMatch))) {
496
0
        fontDef->pixelSize = request.pixelSize;
497
0
    } else {
498
0
        fontDef->pixelSize = desc.size->pixelSize;
499
0
    }
500
0
    fontDef->pointSize     = request.pointSize;
501
502
0
    fontDef->styleHint     = request.styleHint;
503
0
    fontDef->styleStrategy = request.styleStrategy;
504
505
0
    if (!multi)
506
0
        fontDef->weight    = desc.style->key.weight;
507
0
    if (!multi)
508
0
        fontDef->style     = desc.style->key.style;
509
0
    fontDef->fixedPitch    = desc.family->fixedPitch;
510
0
    fontDef->ignorePitch   = false;
511
0
}
512
513
static QStringList familyList(const QFontDef &req)
514
0
{
515
    // list of families to try
516
0
    QStringList family_list;
517
518
0
    family_list << req.families;
519
    // append the substitute list for each family in family_list
520
0
    for (int i = 0, size = family_list.size(); i < size; ++i)
521
0
        family_list += QFont::substitutes(family_list.at(i));
522
523
0
    return family_list;
524
0
}
525
526
Q_GLOBAL_STATIC(QRecursiveMutex, fontDatabaseMutex)
527
528
// used in qguiapplication.cpp
529
void qt_cleanupFontDatabase()
530
0
{
531
0
    auto *db = QFontDatabasePrivate::instance();
532
0
    db->fallbacksCache.clear();
533
0
    db->clearFamilies();
534
0
}
535
536
// used in qfont.cpp
537
QRecursiveMutex *qt_fontdatabase_mutex()
538
0
{
539
0
    return fontDatabaseMutex();
540
0
}
541
542
QFontDatabasePrivate *QFontDatabasePrivate::instance()
543
0
{
544
0
    static QFontDatabasePrivate instance;
545
0
    return &instance;
546
0
}
547
548
void qt_registerFont(const QString &familyName, const QString &stylename,
549
                     const QString &foundryname, int weight,
550
                     QFont::Style style, int stretch, bool antialiased,
551
                     bool scalable, int pixelSize, bool fixedPitch, bool colorFont,
552
                     const QSupportedWritingSystems &writingSystems, void *handle)
553
0
{
554
0
    auto *d = QFontDatabasePrivate::instance();
555
0
    qCDebug(lcFontDb) << "Adding font: familyName" << familyName << "stylename" << stylename << "weight" << weight
556
0
                      << "style" << style << "pixelSize" << pixelSize << "antialiased" << antialiased << "fixed" << fixedPitch << "colorFont" << colorFont;
557
0
    QtFontStyle::Key styleKey;
558
0
    styleKey.style = style;
559
0
    styleKey.weight = weight;
560
0
    styleKey.stretch = stretch;
561
0
    QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::EnsureCreated);
562
0
    f->fixedPitch = fixedPitch;
563
0
    f->colorFont = colorFont;
564
565
0
    for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
566
0
        if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
567
0
            f->writingSystems[i] = QtFontFamily::Supported;
568
0
    }
569
570
0
    QtFontFoundry *foundry = f->foundry(foundryname, true);
571
0
    QtFontStyle *fontStyle = foundry->style(styleKey,
572
0
                                            stylename,
573
0
                                            QtFontFoundry::StyleRetrievalFlags::AllRetrievalFlags);
574
0
    fontStyle->smoothScalable = scalable;
575
0
    fontStyle->antialiased = antialiased;
576
0
    QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
577
0
    if (size->handle) {
578
0
        QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
579
0
        if (integration)
580
0
            integration->fontDatabase()->releaseHandle(size->handle);
581
0
    }
582
0
    size->handle = handle;
583
0
    f->populated = true;
584
0
}
585
586
void qt_registerFontFamily(const QString &familyName)
587
0
{
588
0
    qCDebug(lcFontDb) << "Registering family" << familyName;
589
590
    // Create uninitialized/unpopulated family
591
0
    QFontDatabasePrivate::instance()->family(familyName, QFontDatabasePrivate::EnsureCreated);
592
0
}
593
594
void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
595
0
{
596
0
    if (alias.isEmpty())
597
0
        return;
598
599
0
    qCDebug(lcFontDb) << "Registering alias" << alias << "to family" << familyName;
600
601
0
    auto *d = QFontDatabasePrivate::instance();
602
0
    QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
603
0
    if (!f)
604
0
        return;
605
606
0
    if (f->aliases.contains(alias, Qt::CaseInsensitive))
607
0
        return;
608
609
0
    f->aliases.push_back(alias);
610
0
}
611
612
QString qt_resolveFontFamilyAlias(const QString &alias)
613
0
{
614
0
    if (!alias.isEmpty()) {
615
0
        const auto *d = QFontDatabasePrivate::instance();
616
0
        for (int i = 0; i < d->count; ++i)
617
0
            if (d->families[i]->matchesFamilyName(alias))
618
0
                return d->families[i]->name;
619
0
    }
620
0
    return alias;
621
0
}
622
623
bool qt_isFontFamilyPopulated(const QString &familyName)
624
0
{
625
0
    auto *d = QFontDatabasePrivate::instance();
626
0
    QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
627
0
    return f != nullptr && f->populated;
628
0
}
629
630
/*!
631
    Returns a list of alternative fonts for the specified \a family and
632
    \a style and \a script using the \a styleHint given.
633
634
    Default implementation returns a list of fonts for which \a style and \a script support
635
    has been reported during the font database population.
636
*/
637
QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family,
638
                                                      QFont::Style style,
639
                                                      QFont::StyleHint styleHint,
640
                                                      QFontDatabasePrivate::ExtendedScript script) const
641
0
{
642
0
    Q_UNUSED(family);
643
0
    Q_UNUSED(styleHint);
644
645
0
    QStringList preferredFallbacks;
646
0
    QStringList otherFallbacks;
647
648
0
    auto writingSystem = qt_writing_system_for_script(script);
649
0
    if (writingSystem >= QFontDatabase::WritingSystemsCount)
650
0
        writingSystem = QFontDatabase::Any;
651
652
0
    auto *db = QFontDatabasePrivate::instance();
653
0
    for (int i = 0; i < db->count; ++i) {
654
0
        QtFontFamily *f = db->families[i];
655
656
0
        f->ensurePopulated();
657
658
0
        if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(f, writingSystem))
659
0
            continue;
660
661
0
        for (int j = 0; j < f->count; ++j) {
662
0
            QtFontFoundry *foundry = f->foundries[j];
663
664
0
            for (int k = 0; k < foundry->count; ++k) {
665
0
                QString name = foundry->name.isEmpty()
666
0
                        ? f->name
667
0
                        : f->name + " ["_L1 + foundry->name + u']';
668
0
                if (style == foundry->styles[k]->key.style)
669
0
                    preferredFallbacks.append(name);
670
0
                else
671
0
                    otherFallbacks.append(name);
672
0
            }
673
0
        }
674
0
    }
675
676
0
    return preferredFallbacks + otherFallbacks;
677
0
}
678
679
static QStringList fallbacksForFamily(const QString &family,
680
                                      QFont::Style style,
681
                                      QFont::StyleHint styleHint,
682
                                      QFontDatabasePrivate::ExtendedScript script)
683
0
{
684
0
    QMutexLocker locker(fontDatabaseMutex());
685
0
    auto *db = QFontDatabasePrivate::ensureFontDatabase();
686
687
0
    const QtFontFallbacksCacheKey cacheKey = { family, style, styleHint, script };
688
689
0
    if (const QStringList *fallbacks = db->fallbacksCache.object(cacheKey))
690
0
        return *fallbacks;
691
692
    // make sure that the db has all fallback families
693
0
    QStringList userFallbacks = db->applicationFallbackFontFamilies(script == QFontDatabasePrivate::Script_Latin ? QFontDatabasePrivate::Script_Common : script);
694
0
    QStringList retList = userFallbacks + QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
695
696
0
    QStringList::iterator i;
697
0
    for (i = retList.begin(); i != retList.end(); ++i) {
698
0
        bool contains = false;
699
0
        for (int j = 0; j < db->count; j++) {
700
0
            if (db->families[j]->matchesFamilyName(*i)) {
701
0
                contains = true;
702
0
                break;
703
0
            }
704
0
        }
705
0
        if (!contains) {
706
0
            i = retList.erase(i);
707
0
            --i;
708
0
        }
709
0
    }
710
711
0
    db->fallbacksCache.insert(cacheKey, new QStringList(retList));
712
713
0
    return retList;
714
0
}
715
716
QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QFontDatabasePrivate::ExtendedScript script)
717
0
{
718
0
    QMutexLocker locker(fontDatabaseMutex());
719
0
    return fallbacksForFamily(family, style, styleHint, script);
720
0
}
721
722
QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script,
723
                              const QFontDef &request,
724
                              QtFontFamily *family, QtFontFoundry *foundry,
725
                              QtFontStyle *style, QtFontSize *size)
726
0
{
727
0
    Q_UNUSED(foundry);
728
729
0
    Q_ASSERT(size);
730
0
    QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
731
0
    int pixelSize = size->pixelSize;
732
0
    if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE)
733
0
        || pfdb->fontsAlwaysScalable()) {
734
0
        pixelSize = request.pixelSize;
735
0
    }
736
737
0
    QFontDef def = request;
738
0
    def.pixelSize = pixelSize;
739
740
0
    QFontCache *fontCache = QFontCache::instance();
741
742
0
    QFontCache::Key key(def,script);
743
0
    QFontEngine *engine = fontCache->findEngine(key);
744
0
    if (!engine) {
745
0
        const bool cacheForCommonScript = script != QFontDatabasePrivate::Script_Common
746
0
                && (family->writingSystems[QFontDatabase::Latin] & QtFontFamily::Supported) != 0;
747
748
0
        if (Q_LIKELY(cacheForCommonScript) && script < QChar::ScriptCount) {
749
            // fast path: check if engine was loaded for another script
750
0
            key.script = QChar::Script_Common;
751
0
            engine = fontCache->findEngine(key);
752
0
            key.script = script;
753
0
            if (engine) {
754
                // Also check for OpenType tables when using complex scripts
755
0
                if (Q_UNLIKELY(!engine->supportsScript(QChar::Script(script)))) {
756
0
                    qCInfo(lcFontDb, "OpenType support missing for \"%ls\", script %d",
757
0
                           qUtf16Printable(def.families.constFirst()), script);
758
0
                    return nullptr;
759
0
                }
760
761
0
                engine->isSmoothlyScalable = style->smoothScalable;
762
0
                fontCache->insertEngine(key, engine);
763
0
                return engine;
764
0
            }
765
0
        }
766
767
        // To avoid synthesized stretch we need a matching stretch to be 100 after this point.
768
        // If stretch didn't match exactly we need to calculate the new stretch factor.
769
        // This only done if not matched by styleName.
770
0
        if (style->key.stretch != 0 && request.stretch != 0
771
0
            && (request.styleName.isEmpty() || request.styleName != style->styleName)) {
772
0
            def.stretch = (request.stretch * 100 + style->key.stretch / 2) / style->key.stretch;
773
0
        } else if (request.stretch == QFont::AnyStretch) {
774
0
            def.stretch = 100;
775
0
        }
776
777
0
        engine = pfdb->fontEngine(def, size->handle);
778
0
        if (engine) {
779
            // Also check for OpenType tables when using complex scripts
780
0
            if (script < QChar::ScriptCount && !engine->supportsScript(QChar::Script(script))) {
781
0
                qCInfo(lcFontDb, "OpenType support missing for \"%ls\", script %d",
782
0
                       qUtf16Printable(def.families.constFirst()), script);
783
0
                if (engine->ref.loadRelaxed() == 0)
784
0
                    delete engine;
785
0
                return nullptr;
786
0
            }
787
788
0
            engine->isSmoothlyScalable = style->smoothScalable;
789
0
            fontCache->insertEngine(key, engine);
790
791
0
            if (Q_LIKELY(cacheForCommonScript && !engine->symbol)) {
792
                // cache engine for Common script as well
793
0
                key.script = QChar::Script_Common;
794
0
                if (!fontCache->findEngine(key))
795
0
                    fontCache->insertEngine(key, engine);
796
0
            }
797
0
        }
798
0
    }
799
0
    return engine;
800
0
}
801
802
QFontEngine *QFontDatabasePrivate::loadEngine(int script, const QFontDef &request,
803
                        QtFontFamily *family, QtFontFoundry *foundry,
804
                        QtFontStyle *style, QtFontSize *size)
805
0
{
806
0
    QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size);
807
808
0
    if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
809
0
        Q_TRACE(QFontDatabase_loadEngine, request.families.join(QLatin1Char(';')), request.pointSize);
810
811
0
        QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
812
0
        QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine,
813
0
                                                                QFontDatabasePrivate::ExtendedScript(script));
814
0
        if (!request.fallBackFamilies.isEmpty()) {
815
0
            QStringList fallbacks = request.fallBackFamilies;
816
817
0
            QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
818
0
            if (styleHint == QFont::AnyStyle && request.fixedPitch)
819
0
                styleHint = QFont::TypeWriter;
820
821
0
            fallbacks += fallbacksForFamily(family->name,
822
0
                                            QFont::Style(style->key.style),
823
0
                                            styleHint,
824
0
                                            QFontDatabasePrivate::ExtendedScript(script));
825
826
0
            pfMultiEngine->setFallbackFamiliesList(fallbacks);
827
0
        }
828
0
        engine = pfMultiEngine;
829
830
        // Cache Multi font engine as well in case we got the single
831
        // font engine when we are actually looking for a Multi one
832
0
        QFontCache::Key key(request, script, 1);
833
0
        QFontCache::instance()->insertEngine(key, engine);
834
0
    }
835
836
0
    return engine;
837
0
}
838
839
QtFontStyle::~QtFontStyle()
840
0
{
841
0
   while (count) {
842
       // bitfield count-- in while condition does not work correctly in mwccsym2
843
0
       count--;
844
0
       QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
845
0
       if (integration)
846
0
           integration->fontDatabase()->releaseHandle(pixelSizes[count].handle);
847
0
   }
848
849
0
   free(pixelSizes);
850
0
}
851
852
static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey,
853
                              const QString &styleName = QString())
854
0
{
855
0
    int best = 0;
856
0
    int dist = 0xffff;
857
858
0
    for ( int i = 0; i < foundry->count; i++ ) {
859
0
        QtFontStyle *style = foundry->styles[i];
860
861
0
        if (!styleName.isEmpty() && styleName == style->styleName) {
862
0
            dist = 0;
863
0
            best = i;
864
0
            break;
865
0
        }
866
867
0
        int d = qAbs( (int(styleKey.weight) - int(style->key.weight)) / 10 );
868
869
0
        if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
870
0
            d += qAbs( styleKey.stretch - style->key.stretch );
871
0
        }
872
873
0
        if (styleKey.style != style->key.style) {
874
0
            if (styleKey.style != QFont::StyleNormal && style->key.style != QFont::StyleNormal)
875
                // one is italic, the other oblique
876
0
                d += 0x0001;
877
0
            else
878
0
                d += 0x1000;
879
0
        }
880
881
0
        if ( d < dist ) {
882
0
            best = i;
883
0
            dist = d;
884
0
        }
885
0
    }
886
887
0
    qCDebug(lcFontMatch,  "          best style has distance 0x%x", dist );
888
0
    return foundry->styles[best];
889
0
}
890
891
892
unsigned int QFontDatabasePrivate::bestFoundry(int script, unsigned int score, int styleStrategy,
893
                         const QtFontFamily *family, const QString &foundry_name,
894
                         QtFontStyle::Key styleKey, int pixelSize, char pitch,
895
                         QtFontDesc *desc, const QString &styleName)
896
0
{
897
0
    Q_UNUSED(script);
898
0
    Q_UNUSED(pitch);
899
900
0
    desc->foundry = nullptr;
901
0
    desc->style = nullptr;
902
0
    desc->size = nullptr;
903
904
0
    qCDebug(lcFontMatch, "  REMARK: looking for best foundry for family '%s'%s [%d]",
905
0
            family->name.toLatin1().constData(),
906
0
            family->colorFont ? " (color font)" : "",
907
0
            family->count);
908
909
0
    for (int x = 0; x < family->count; ++x) {
910
0
        QtFontFoundry *foundry = family->foundries[x];
911
0
        if (!foundry_name.isEmpty() && foundry->name.compare(foundry_name, Qt::CaseInsensitive) != 0)
912
0
            continue;
913
914
0
        qCDebug(lcFontMatch, "          looking for matching style in foundry '%s' %d",
915
0
                 foundry->name.isEmpty() ? "-- none --" : foundry->name.toLatin1().constData(), foundry->count);
916
917
0
        QtFontStyle *style = bestStyle(foundry, styleKey, styleName);
918
919
0
        if (!style->smoothScalable && (styleStrategy & QFont::ForceOutline)) {
920
0
            qCDebug(lcFontMatch, "            ForceOutline set, but not smoothly scalable");
921
0
            continue;
922
0
        }
923
924
0
        int px = -1;
925
0
        QtFontSize *size = nullptr;
926
927
        // 1. see if we have an exact matching size
928
0
        if (!(styleStrategy & QFont::ForceOutline)) {
929
0
            size = style->pixelSize(pixelSize);
930
0
            if (size) {
931
0
                qCDebug(lcFontMatch, "          found exact size match (%d pixels)", size->pixelSize);
932
0
                px = size->pixelSize;
933
0
            }
934
0
        }
935
936
        // 2. see if we have a smoothly scalable font
937
0
        if (!size && style->smoothScalable && ! (styleStrategy & QFont::PreferBitmap)) {
938
0
            size = style->pixelSize(SMOOTH_SCALABLE);
939
0
            if (size) {
940
0
                qCDebug(lcFontMatch, "          found smoothly scalable font (%d pixels)", pixelSize);
941
0
                px = pixelSize;
942
0
            }
943
0
        }
944
945
        // 3. see if we have a bitmap scalable font
946
0
        if (!size && style->bitmapScalable && (styleStrategy & QFont::PreferMatch)) {
947
0
            size = style->pixelSize(0);
948
0
            if (size) {
949
0
                qCDebug(lcFontMatch, "          found bitmap scalable font (%d pixels)", pixelSize);
950
0
                px = pixelSize;
951
0
            }
952
0
        }
953
954
955
        // 4. find closest size match
956
0
        if (! size) {
957
0
            unsigned int distance = ~0u;
958
0
            for (int x = 0; x < style->count; ++x) {
959
960
0
                unsigned int d;
961
0
                if (style->pixelSizes[x].pixelSize < pixelSize) {
962
                    // penalize sizes that are smaller than the
963
                    // requested size, due to truncation from floating
964
                    // point to integer conversions
965
0
                    d = pixelSize - style->pixelSizes[x].pixelSize + 1;
966
0
                } else {
967
0
                    d = style->pixelSizes[x].pixelSize - pixelSize;
968
0
                }
969
970
0
                if (d < distance) {
971
0
                    distance = d;
972
0
                    size = style->pixelSizes + x;
973
0
                    qCDebug(lcFontMatch, "          best size so far: %3d (%d)", size->pixelSize, pixelSize);
974
0
                }
975
0
            }
976
977
0
            if (!size) {
978
0
                qCDebug(lcFontMatch, "          no size supports the script we want");
979
0
                continue;
980
0
            }
981
982
0
            if (style->bitmapScalable && ! (styleStrategy & QFont::PreferQuality) &&
983
0
                (distance * 10 / pixelSize) >= 2) {
984
                // the closest size is not close enough, go ahead and
985
                // use a bitmap scaled font
986
0
                size = style->pixelSize(0);
987
0
                px = pixelSize;
988
0
            } else {
989
0
                px = size->pixelSize;
990
0
            }
991
0
        }
992
993
994
0
        unsigned int this_score = 0x0000;
995
0
        enum {
996
0
            PitchMismatch       = 0x4000,
997
0
            StyleMismatch       = 0x2000,
998
0
            BitmapScaledPenalty = 0x1000
999
0
        };
1000
0
        if (pitch != '*') {
1001
0
            if ((pitch == 'm' && !family->fixedPitch)
1002
0
                || (pitch == 'p' && family->fixedPitch))
1003
0
                this_score += PitchMismatch;
1004
0
        }
1005
0
        if (styleKey != style->key)
1006
0
            this_score += StyleMismatch;
1007
0
        if (!style->smoothScalable && px != size->pixelSize) // bitmap scaled
1008
0
            this_score += BitmapScaledPenalty;
1009
0
        if (px != pixelSize) // close, but not exact, size match
1010
0
            this_score += qAbs(px - pixelSize);
1011
1012
0
        if (this_score < score) {
1013
0
            qCDebug(lcFontMatch, "          found a match: score %x best score so far %x",
1014
0
                     this_score, score);
1015
1016
0
            score = this_score;
1017
0
            desc->foundry = foundry;
1018
0
            desc->style = style;
1019
0
            desc->size = size;
1020
0
        } else {
1021
0
            qCDebug(lcFontMatch, "          score %x no better than best %x", this_score, score);
1022
0
        }
1023
0
    }
1024
1025
0
    return score;
1026
0
}
1027
1028
static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
1029
0
{
1030
0
    if (familyName.isEmpty())
1031
0
        return true;
1032
0
    return f->matchesFamilyName(familyName);
1033
0
}
1034
1035
/*!
1036
    \internal
1037
1038
    Tries to find the best match for a given request and family/foundry
1039
*/
1040
int QFontDatabasePrivate::match(int script, const QFontDef &request, const QString &family_name,
1041
                     const QString &foundry_name, QtFontDesc *desc, const QList<int> &blacklistedFamilies,
1042
                     unsigned int *resultingScore)
1043
0
{
1044
0
    int result = -1;
1045
1046
0
    QtFontStyle::Key styleKey;
1047
0
    styleKey.style = request.style;
1048
0
    styleKey.weight = request.weight;
1049
    // Prefer a stretch closest to 100.
1050
0
    styleKey.stretch = request.stretch ? request.stretch : 100;
1051
0
    char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
1052
1053
1054
0
    qCDebug(lcFontMatch, "QFontDatabasePrivate::match\n"
1055
0
             "  request:\n"
1056
0
             "    family: %s [%s], script: %d\n"
1057
0
             "    styleName: %s\n"
1058
0
             "    weight: %d, style: %d\n"
1059
0
             "    stretch: %d\n"
1060
0
             "    pixelSize: %g\n"
1061
0
             "    pitch: %c",
1062
0
             family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
1063
0
             foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(), script,
1064
0
             request.styleName.isEmpty() ? "-- any --" : request.styleName.toLatin1().constData(),
1065
0
             request.weight, request.style, request.stretch, request.pixelSize, pitch);
1066
1067
0
    desc->family = nullptr;
1068
0
    desc->foundry = nullptr;
1069
0
    desc->style = nullptr;
1070
0
    desc->size = nullptr;
1071
1072
0
    unsigned int score = ~0u;
1073
1074
0
    QMutexLocker locker(fontDatabaseMutex());
1075
0
    QFontDatabasePrivate::ensureFontDatabase();
1076
1077
0
    auto writingSystem = qt_writing_system_for_script(script);
1078
0
    if (writingSystem >= QFontDatabase::WritingSystemsCount)
1079
0
        writingSystem = QFontDatabase::Any;
1080
1081
0
    auto *db = QFontDatabasePrivate::instance();
1082
0
    for (int x = 0; x < db->count; ++x) {
1083
0
        if (blacklistedFamilies.contains(x))
1084
0
            continue;
1085
0
        QtFontDesc test;
1086
0
        test.family = db->families[x];
1087
1088
0
        if (!matchFamilyName(family_name, test.family))
1089
0
            continue;
1090
0
        if (!test.family->ensurePopulated())
1091
0
            continue;
1092
1093
        // Check if family is supported in the script we want
1094
0
        if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(test.family, writingSystem))
1095
0
            continue;
1096
1097
        // Check if we require a color font and check for match
1098
0
        if (script == QFontDatabasePrivate::Script_Emoji && !test.family->colorFont)
1099
0
            continue;
1100
1101
        // as we know the script is supported, we can be sure
1102
        // to find a matching font here.
1103
0
        unsigned int newscore =
1104
0
            bestFoundry(script, score, request.styleStrategy,
1105
0
                        test.family, foundry_name, styleKey, request.pixelSize, pitch,
1106
0
                        &test, request.styleName);
1107
0
        if (test.foundry == nullptr && !foundry_name.isEmpty()) {
1108
            // the specific foundry was not found, so look for
1109
            // any foundry matching our requirements
1110
0
            newscore = bestFoundry(script, score, request.styleStrategy, test.family,
1111
0
                                   QString(), styleKey, request.pixelSize,
1112
0
                                   pitch, &test, request.styleName);
1113
0
        }
1114
1115
0
        if (newscore < score) {
1116
0
            result = x;
1117
0
            score = newscore;
1118
0
            *desc = test;
1119
0
        }
1120
0
        if (newscore < 10) // xlfd instead of FT... just accept it
1121
0
            break;
1122
0
    }
1123
1124
0
    if (resultingScore != nullptr)
1125
0
        *resultingScore = score;
1126
1127
0
    return result;
1128
0
}
1129
1130
static QString styleStringHelper(int weight, QFont::Style style)
1131
0
{
1132
0
    QString result;
1133
0
    if (weight > QFont::Normal) {
1134
0
        if (weight >= QFont::Black)
1135
0
            result = QCoreApplication::translate("QFontDatabase", "Black");
1136
0
        else if (weight >= QFont::ExtraBold)
1137
0
            result = QCoreApplication::translate("QFontDatabase", "Extra Bold");
1138
0
        else if (weight >= QFont::Bold)
1139
0
            result = QCoreApplication::translate("QFontDatabase", "Bold");
1140
0
        else if (weight >= QFont::DemiBold)
1141
0
            result = QCoreApplication::translate("QFontDatabase", "Demi Bold");
1142
0
        else if (weight >= QFont::Medium)
1143
0
            result = QCoreApplication::translate("QFontDatabase", "Medium", "The Medium font weight");
1144
0
    } else {
1145
0
        if (weight <= QFont::Thin)
1146
0
            result = QCoreApplication::translate("QFontDatabase", "Thin");
1147
0
        else if (weight <= QFont::ExtraLight)
1148
0
            result = QCoreApplication::translate("QFontDatabase", "Extra Light");
1149
0
        else if (weight <= QFont::Light)
1150
0
            result = QCoreApplication::translate("QFontDatabase", "Light");
1151
0
    }
1152
1153
0
    if (style == QFont::StyleItalic)
1154
0
        result += u' ' + QCoreApplication::translate("QFontDatabase", "Italic");
1155
0
    else if (style == QFont::StyleOblique)
1156
0
        result += u' ' + QCoreApplication::translate("QFontDatabase", "Oblique");
1157
1158
0
    if (result.isEmpty())
1159
0
        result = QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight");
1160
1161
0
    return result.simplified();
1162
0
}
1163
1164
/*!
1165
    Returns a string that describes the style of the \a font. For
1166
    example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
1167
    string may be returned.
1168
*/
1169
QString QFontDatabase::styleString(const QFont &font)
1170
0
{
1171
0
    return font.styleName().isEmpty() ? styleStringHelper(font.weight(), font.style())
1172
0
                                      : font.styleName();
1173
0
}
1174
1175
/*!
1176
    Returns a string that describes the style of the \a fontInfo. For
1177
    example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
1178
    string may be returned.
1179
*/
1180
QString QFontDatabase::styleString(const QFontInfo &fontInfo)
1181
0
{
1182
0
    return fontInfo.styleName().isEmpty() ? styleStringHelper(fontInfo.weight(), fontInfo.style())
1183
0
                                          : fontInfo.styleName();
1184
0
}
1185
1186
1187
/*!
1188
    \class QFontDatabase
1189
    \threadsafe
1190
    \inmodule QtGui
1191
1192
    \brief The QFontDatabase class provides information about the fonts available in the underlying window system.
1193
1194
    \ingroup appearance
1195
1196
    The most common uses of this class are to query the database for
1197
    the list of font families() and for the pointSizes() and styles()
1198
    that are available for each family. An alternative to pointSizes()
1199
    is smoothSizes() which returns the sizes at which a given family
1200
    and style will look attractive.
1201
1202
    If the font family is available from two or more foundries the
1203
    foundry name is included in the family name; for example:
1204
    "Helvetica [Adobe]" and "Helvetica [Cronyx]". When you specify a
1205
    family, you can either use the old hyphenated "foundry-family"
1206
    format or the bracketed "family [foundry]" format; for example:
1207
    "Cronyx-Helvetica" or "Helvetica [Cronyx]". If the family has a
1208
    foundry it is always returned using the bracketed format, as is
1209
    the case with the value returned by families().
1210
1211
    The font() function returns a QFont given a family, style and
1212
    point size.
1213
1214
    A family and style combination can be checked to see if it is
1215
    italic() or bold(), and to retrieve its weight(). Similarly we can
1216
    call isBitmapScalable(), isSmoothlyScalable(), isScalable() and
1217
    isFixedPitch().
1218
1219
    Use the styleString() to obtain a text version of a style.
1220
1221
    The QFontDatabase class provides some helper functions, for
1222
    example, standardSizes(). You can retrieve the description of a
1223
    writing system using writingSystemName(), and a sample of
1224
    characters in a writing system with writingSystemSample().
1225
1226
    Example:
1227
1228
    \snippet qfontdatabase/qfontdatabase_snippets.cpp 0
1229
1230
    This example gets the list of font families, the list of
1231
    styles for each family, and the point sizes that are available for
1232
    each combination of family and style, displaying this information
1233
    in a tree view.
1234
1235
    \sa QFont, QFontInfo, QFontMetrics
1236
*/
1237
1238
/*!
1239
    \fn QFontDatabase::QFontDatabase()
1240
    \deprecated [6.0] Call the class methods as static functions instead.
1241
1242
    Creates a font database object.
1243
*/
1244
1245
/*!
1246
    \enum QFontDatabase::WritingSystem
1247
1248
    \value Any
1249
    \value Latin
1250
    \value Greek
1251
    \value Cyrillic
1252
    \value Armenian
1253
    \value Hebrew
1254
    \value Arabic
1255
    \value Syriac
1256
    \value Thaana
1257
    \value Devanagari
1258
    \value Bengali
1259
    \value Gurmukhi
1260
    \value Gujarati
1261
    \value Oriya
1262
    \value Tamil
1263
    \value Telugu
1264
    \value Kannada
1265
    \value Malayalam
1266
    \value Sinhala
1267
    \value Thai
1268
    \value Lao
1269
    \value Tibetan
1270
    \value Myanmar
1271
    \value Georgian
1272
    \value Khmer
1273
    \value SimplifiedChinese
1274
    \value TraditionalChinese
1275
    \value Japanese
1276
    \value Korean
1277
    \value Vietnamese
1278
    \value Symbol
1279
    \value Other (the same as Symbol)
1280
    \value Ogham
1281
    \value Runic
1282
    \value Nko
1283
1284
    \omitvalue WritingSystemsCount
1285
*/
1286
1287
/*!
1288
    \enum QFontDatabase::SystemFont
1289
1290
    \value GeneralFont              The default system font.
1291
    \value FixedFont                The fixed font that the system recommends.
1292
    \value TitleFont                The system standard font for titles.
1293
    \value SmallestReadableFont     The smallest readable system font.
1294
1295
    \since 5.2
1296
*/
1297
1298
/*!
1299
    \class QFontDatabasePrivate
1300
    \internal
1301
1302
    Singleton implementation of the public QFontDatabase APIs,
1303
    accessed through QFontDatabasePrivate::instance().
1304
1305
    The database is organized in multiple levels:
1306
1307
      - QFontDatabasePrivate::families
1308
        - QtFontFamily::foundries
1309
          - QtFontFoundry::styles
1310
            - QtFontStyle::sizes
1311
              - QtFontSize::pixelSize
1312
1313
    The font database is the single source of truth when doing
1314
    font matching, so the database must be sufficiently filled
1315
    before attempting a match.
1316
1317
    The database is populated (filled) from two sources:
1318
1319
     1. The system (platform's) view of the available fonts
1320
1321
        Initiated via QFontDatabasePrivate::populateFontDatabase().
1322
1323
        a. Can be registered lazily by family only, by calling
1324
           QPlatformFontDatabase::registerFontFamily(), and later
1325
           populated via QPlatformFontDatabase::populateFamily().
1326
1327
        b. Or fully registered with all styles, by calling
1328
           QPlatformFontDatabase::registerFont().
1329
1330
     2. The fonts registered by the application via Qt APIs
1331
1332
        Initiated via QFontDatabase::addApplicationFont() and
1333
        QFontDatabase::addApplicationFontFromData().
1334
1335
        Application fonts are always fully registered when added.
1336
1337
    Fonts can be added at any time, so the database may grow even
1338
    after QFontDatabasePrivate::populateFontDatabase() has been
1339
    completed.
1340
1341
    The database does not support granular removal of fonts,
1342
    so if the system fonts change, or an application font is
1343
    removed, the font database will be cleared and then filled
1344
    from scratch, via QFontDatabasePrivate:invalidate() and
1345
    QFontDatabasePrivate::ensureFontDatabase().
1346
*/
1347
1348
/*!
1349
    \internal
1350
1351
    Initializes the font database if necessary and returns its
1352
    pointer. Mutex lock must be held when calling this function.
1353
*/
1354
QFontDatabasePrivate *QFontDatabasePrivate::ensureFontDatabase()
1355
0
{
1356
0
    auto *d = QFontDatabasePrivate::instance();
1357
0
    if (!d->populated) {
1358
        // The font database may have been partially populated, but to ensure
1359
        // we can answer queries for any platform- or user-provided family we
1360
        // need to fully populate it now.
1361
0
        qCDebug(lcFontDb) << "Populating font database";
1362
1363
0
        if (Q_UNLIKELY(qGuiApp == nullptr || QGuiApplicationPrivate::platformIntegration() == nullptr))
1364
0
            qFatal("QFontDatabase: Must construct a QGuiApplication before accessing QFontDatabase");
1365
1366
0
        auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
1367
0
        platformFontDatabase->populateFontDatabase();
1368
1369
0
        for (int i = 0; i < d->applicationFonts.size(); i++) {
1370
0
            auto *font = &d->applicationFonts[i];
1371
0
            if (!font->isNull() && !font->isPopulated())
1372
0
                platformFontDatabase->addApplicationFont(font->data, font->fileName, font);
1373
0
        }
1374
1375
        // Note: Both application fonts and platform fonts may be added
1376
        // after this initial population, so the only thing we are tracking
1377
        // is whether we've done our part in ensuring a filled font database.
1378
0
        d->populated = true;
1379
0
    }
1380
0
    return d;
1381
0
}
1382
1383
/*!
1384
    Returns a sorted list of the available writing systems. This is
1385
    list generated from information about all installed fonts on the
1386
    system.
1387
1388
    \sa families()
1389
*/
1390
QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems()
1391
0
{
1392
0
    QMutexLocker locker(fontDatabaseMutex());
1393
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1394
1395
0
    quint64 writingSystemsFound = 0;
1396
0
    static_assert(WritingSystemsCount < 64);
1397
1398
0
    for (int i = 0; i < d->count; ++i) {
1399
0
        QtFontFamily *family = d->families[i];
1400
0
        if (!family->ensurePopulated())
1401
0
            continue;
1402
1403
0
        if (family->count == 0)
1404
0
            continue;
1405
0
        for (uint x = Latin; x < uint(WritingSystemsCount); ++x) {
1406
0
            if (family->writingSystems[x] & QtFontFamily::Supported)
1407
0
                writingSystemsFound |= quint64(1) << x;
1408
0
        }
1409
0
    }
1410
1411
    // mutex protection no longer needed - just working on local data now:
1412
0
    locker.unlock();
1413
1414
0
    QList<WritingSystem> list;
1415
0
    list.reserve(qPopulationCount(writingSystemsFound));
1416
0
    for (uint x = Latin ; x < uint(WritingSystemsCount); ++x) {
1417
0
        if (writingSystemsFound & (quint64(1) << x))
1418
0
            list.push_back(WritingSystem(x));
1419
0
    }
1420
0
    return list;
1421
0
}
1422
1423
1424
/*!
1425
    Returns a sorted list of the writing systems supported by a given
1426
    font \a family.
1427
1428
    \sa families()
1429
*/
1430
QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family)
1431
0
{
1432
0
    QString familyName, foundryName;
1433
0
    parseFontName(family, foundryName, familyName);
1434
1435
0
    QMutexLocker locker(fontDatabaseMutex());
1436
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1437
1438
0
    QList<WritingSystem> list;
1439
0
    QtFontFamily *f = d->family(familyName);
1440
0
    if (!f || f->count == 0)
1441
0
        return list;
1442
1443
0
    for (int x = Latin; x < WritingSystemsCount; ++x) {
1444
0
        const WritingSystem writingSystem = WritingSystem(x);
1445
0
        if (f->writingSystems[writingSystem] & QtFontFamily::Supported)
1446
0
            list.append(writingSystem);
1447
0
    }
1448
0
    return list;
1449
0
}
1450
1451
1452
/*!
1453
    Returns a sorted list of the available font families which support
1454
    the \a writingSystem.
1455
1456
    If a family exists in several foundries, the returned name for
1457
    that font is in the form "family [foundry]". Examples: "Times
1458
    [Adobe]", "Times [Cronyx]", "Palatino".
1459
1460
    \sa writingSystems()
1461
*/
1462
QStringList QFontDatabase::families(WritingSystem writingSystem)
1463
0
{
1464
0
    QMutexLocker locker(fontDatabaseMutex());
1465
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1466
1467
0
    QStringList flist;
1468
0
    for (int i = 0; i < d->count; i++) {
1469
0
        QtFontFamily *f = d->families[i];
1470
0
        if (f->populated && f->count == 0)
1471
0
            continue;
1472
0
        if (writingSystem != Any) {
1473
0
            if (!f->ensurePopulated())
1474
0
                continue;
1475
0
            if (f->writingSystems[writingSystem] != QtFontFamily::Supported)
1476
0
                continue;
1477
0
        }
1478
0
        if (!f->populated || f->count == 1) {
1479
0
            flist.append(f->name);
1480
0
        } else {
1481
0
            for (int j = 0; j < f->count; j++) {
1482
0
                QString str = f->name;
1483
0
                QString foundry = f->foundries[j]->name;
1484
0
                if (!foundry.isEmpty()) {
1485
0
                    str += " ["_L1;
1486
0
                    str += foundry;
1487
0
                    str += u']';
1488
0
                }
1489
0
                flist.append(str);
1490
0
            }
1491
0
        }
1492
0
    }
1493
0
    return flist;
1494
0
}
1495
1496
/*!
1497
    Returns a list of the styles available for the font family \a
1498
    family. Some example styles: "Light", "Light Italic", "Bold",
1499
    "Oblique", "Demi". The list may be empty.
1500
1501
    \sa families()
1502
*/
1503
QStringList QFontDatabase::styles(const QString &family)
1504
0
{
1505
0
    QString familyName, foundryName;
1506
0
    parseFontName(family, foundryName, familyName);
1507
1508
0
    QMutexLocker locker(fontDatabaseMutex());
1509
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1510
1511
0
    QStringList l;
1512
0
    QtFontFamily *f = d->family(familyName);
1513
0
    if (!f)
1514
0
        return l;
1515
1516
0
    QtFontFoundry allStyles(foundryName);
1517
0
    for (int j = 0; j < f->count; j++) {
1518
0
        QtFontFoundry *foundry = f->foundries[j];
1519
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1520
0
            for (int k = 0; k < foundry->count; k++) {
1521
0
                QtFontStyle::Key ke(foundry->styles[k]->key);
1522
0
                ke.stretch = 0;
1523
0
                allStyles.style(ke,
1524
0
                                foundry->styles[k]->styleName,
1525
0
                                QtFontFoundry::AddWhenMissing);
1526
0
            }
1527
0
        }
1528
0
    }
1529
1530
0
    l.reserve(allStyles.count);
1531
0
    for (int i = 0; i < allStyles.count; i++) {
1532
0
        l.append(allStyles.styles[i]->styleName.isEmpty() ?
1533
0
                 styleStringHelper(allStyles.styles[i]->key.weight,
1534
0
                                   (QFont::Style)allStyles.styles[i]->key.style) :
1535
0
                 allStyles.styles[i]->styleName);
1536
0
    }
1537
0
    return l;
1538
0
}
1539
1540
/*!
1541
    Returns \c true if the font that has family \a family and style \a
1542
    style is fixed pitch; otherwise returns \c false.
1543
*/
1544
1545
bool QFontDatabase::isFixedPitch(const QString &family,
1546
                                 const QString &style)
1547
0
{
1548
0
    Q_UNUSED(style);
1549
1550
0
    QString familyName, foundryName;
1551
0
    parseFontName(family, foundryName, familyName);
1552
1553
0
    QMutexLocker locker(fontDatabaseMutex());
1554
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1555
1556
0
    QtFontFamily *f = d->family(familyName);
1557
0
    return (f && f->fixedPitch);
1558
0
}
1559
1560
/*!
1561
    Returns \c true if the font that has family \a family and style \a
1562
    style is a scalable bitmap font; otherwise returns \c false. Scaling
1563
    a bitmap font usually produces an unattractive hardly readable
1564
    result, because the pixels of the font are scaled. If you need to
1565
    scale a bitmap font it is better to scale it to one of the fixed
1566
    sizes returned by smoothSizes().
1567
1568
    \sa isScalable(), isSmoothlyScalable()
1569
*/
1570
bool QFontDatabase::isBitmapScalable(const QString &family,
1571
                                      const QString &style)
1572
0
{
1573
0
    QString familyName, foundryName;
1574
0
    parseFontName(family, foundryName, familyName);
1575
1576
0
    QMutexLocker locker(fontDatabaseMutex());
1577
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1578
1579
0
    QtFontFamily *f = d->family(familyName);
1580
0
    if (!f)
1581
0
        return false;
1582
1583
0
    QtFontStyle::Key styleKey(style);
1584
0
    for (int j = 0; j < f->count; j++) {
1585
0
        QtFontFoundry *foundry = f->foundries[j];
1586
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1587
0
            for (int k = 0; k < foundry->count; k++)
1588
0
                if ((style.isEmpty() ||
1589
0
                     foundry->styles[k]->styleName == style ||
1590
0
                     foundry->styles[k]->key == styleKey)
1591
0
                    && foundry->styles[k]->bitmapScalable && !foundry->styles[k]->smoothScalable) {
1592
0
                    return true;
1593
0
                }
1594
0
        }
1595
0
    }
1596
0
    return false;
1597
0
}
1598
1599
1600
/*!
1601
    Returns \c true if the font that has family \a family and style \a
1602
    style is smoothly scalable; otherwise returns \c false. If this
1603
    function returns \c true, it's safe to scale this font to any size,
1604
    and the result will always look attractive.
1605
1606
    \sa isScalable(), isBitmapScalable()
1607
*/
1608
bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style)
1609
0
{
1610
0
    QString familyName, foundryName;
1611
0
    parseFontName(family, foundryName, familyName);
1612
1613
0
    QMutexLocker locker(fontDatabaseMutex());
1614
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1615
1616
0
    QtFontFamily *f = d->family(familyName);
1617
0
    if (!f) {
1618
0
        for (int i = 0; i < d->count; i++) {
1619
0
            if (d->families[i]->matchesFamilyName(familyName)) {
1620
0
                f = d->families[i];
1621
0
                if (f->ensurePopulated())
1622
0
                    break;
1623
0
            }
1624
0
        }
1625
0
    }
1626
0
    if (!f)
1627
0
        return false;
1628
1629
0
    const QtFontStyle::Key styleKey(style);
1630
0
    for (int j = 0; j < f->count; j++) {
1631
0
        QtFontFoundry *foundry = f->foundries[j];
1632
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1633
0
            for (int k = 0; k < foundry->count; k++) {
1634
0
                const QtFontStyle *fontStyle = foundry->styles[k];
1635
0
                const bool smoothScalable =
1636
0
                        fontStyle->smoothScalable
1637
0
                        && ((style.isEmpty()
1638
0
                             || fontStyle->styleName == style
1639
0
                             || fontStyle->key == styleKey)
1640
0
                            || (fontStyle->styleName.isEmpty()
1641
0
                                && style == styleStringHelper(fontStyle->key.weight,
1642
0
                                                              QFont::Style(fontStyle->key.style))));
1643
0
                if (smoothScalable)
1644
0
                    return true;
1645
0
            }
1646
0
        }
1647
0
    }
1648
0
    return false;
1649
0
}
1650
1651
/*!
1652
    Returns \c true if the font that has family \a family and style \a
1653
    style is scalable; otherwise returns \c false.
1654
1655
    \sa isBitmapScalable(), isSmoothlyScalable()
1656
*/
1657
bool  QFontDatabase::isScalable(const QString &family,
1658
                                 const QString &style)
1659
0
{
1660
0
    QMutexLocker locker(fontDatabaseMutex());
1661
0
    if (isSmoothlyScalable(family, style))
1662
0
        return true;
1663
0
    return isBitmapScalable(family, style);
1664
0
}
1665
1666
1667
/*!
1668
    Returns a list of the point sizes available for the font that has
1669
    family \a family and style \a styleName. The list may be empty.
1670
1671
    \sa smoothSizes(), standardSizes()
1672
*/
1673
QList<int> QFontDatabase::pointSizes(const QString &family,
1674
                                     const QString &styleName)
1675
0
{
1676
0
    if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
1677
0
        return standardSizes();
1678
1679
0
    QString familyName, foundryName;
1680
0
    parseFontName(family, foundryName, familyName);
1681
1682
0
    QMutexLocker locker(fontDatabaseMutex());
1683
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1684
1685
0
    QList<int> sizes;
1686
1687
0
    QtFontFamily *fam = d->family(familyName);
1688
0
    if (!fam) return sizes;
1689
1690
1691
0
    const int dpi = qt_defaultDpiY(); // embedded
1692
1693
0
    QtFontStyle::Key styleKey(styleName);
1694
0
    for (int j = 0; j < fam->count; j++) {
1695
0
        QtFontFoundry *foundry = fam->foundries[j];
1696
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1697
0
            QtFontStyle *style = foundry->style(styleKey, styleName);
1698
0
            if (!style) continue;
1699
1700
0
            if (style->smoothScalable)
1701
0
                return standardSizes();
1702
1703
0
            for (int l = 0; l < style->count; l++) {
1704
0
                const QtFontSize *size = style->pixelSizes + l;
1705
1706
0
                if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
1707
0
                    const int pointSize = qRound(size->pixelSize * 72.0 / dpi);
1708
0
                    if (! sizes.contains(pointSize))
1709
0
                        sizes.append(pointSize);
1710
0
                }
1711
0
            }
1712
0
        }
1713
0
    }
1714
1715
0
    std::sort(sizes.begin(), sizes.end());
1716
0
    return sizes;
1717
0
}
1718
1719
/*!
1720
    Returns a QFont object that has family \a family, style \a style
1721
    and point size \a pointSize. If no matching font could be created,
1722
    a QFont object that uses the application's default font is
1723
    returned.
1724
*/
1725
QFont QFontDatabase::font(const QString &family, const QString &style,
1726
                          int pointSize)
1727
0
{
1728
0
    QString familyName, foundryName;
1729
0
    parseFontName(family, foundryName, familyName);
1730
0
    QMutexLocker locker(fontDatabaseMutex());
1731
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1732
1733
0
    QtFontFoundry allStyles(foundryName);
1734
0
    QtFontFamily *f = d->family(familyName);
1735
0
    if (!f) return QGuiApplication::font();
1736
1737
0
    for (int j = 0; j < f->count; j++) {
1738
0
        QtFontFoundry *foundry = f->foundries[j];
1739
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1740
0
            for (int k = 0; k < foundry->count; k++) {
1741
0
                allStyles.style(foundry->styles[k]->key,
1742
0
                                foundry->styles[k]->styleName,
1743
0
                                QtFontFoundry::AddWhenMissing);
1744
0
            }
1745
0
        }
1746
0
    }
1747
1748
0
    QtFontStyle::Key styleKey(style);
1749
0
    QtFontStyle *s = bestStyle(&allStyles, styleKey, style);
1750
1751
0
    if (!s) // no styles found?
1752
0
        return QGuiApplication::font();
1753
1754
0
    QFont fnt(QStringList{family}, pointSize, s->key.weight);
1755
0
    fnt.setStyle((QFont::Style)s->key.style);
1756
0
    if (!s->styleName.isEmpty())
1757
0
        fnt.setStyleName(s->styleName);
1758
0
    return fnt;
1759
0
}
1760
1761
1762
/*!
1763
    Returns the point sizes of a font that has family \a family and
1764
    style \a styleName that will look attractive. The list may be empty.
1765
    For non-scalable fonts and bitmap scalable fonts, this function
1766
    is equivalent to pointSizes().
1767
1768
  \sa pointSizes(), standardSizes()
1769
*/
1770
QList<int> QFontDatabase::smoothSizes(const QString &family,
1771
                                            const QString &styleName)
1772
0
{
1773
0
    if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
1774
0
        return standardSizes();
1775
1776
0
    QString familyName, foundryName;
1777
0
    parseFontName(family, foundryName, familyName);
1778
1779
0
    QMutexLocker locker(fontDatabaseMutex());
1780
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1781
1782
0
    QList<int> sizes;
1783
1784
0
    QtFontFamily *fam = d->family(familyName);
1785
0
    if (!fam)
1786
0
        return sizes;
1787
1788
0
    const int dpi = qt_defaultDpiY(); // embedded
1789
1790
0
    QtFontStyle::Key styleKey(styleName);
1791
0
    for (int j = 0; j < fam->count; j++) {
1792
0
        QtFontFoundry *foundry = fam->foundries[j];
1793
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1794
0
            QtFontStyle *style = foundry->style(styleKey, styleName);
1795
0
            if (!style) continue;
1796
1797
0
            if (style->smoothScalable)
1798
0
                return QFontDatabase::standardSizes();
1799
1800
0
            for (int l = 0; l < style->count; l++) {
1801
0
                const QtFontSize *size = style->pixelSizes + l;
1802
1803
0
                if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
1804
0
                    const int pointSize = qRound(size->pixelSize * 72.0 / dpi);
1805
0
                    if (! sizes.contains(pointSize))
1806
0
                        sizes.append(pointSize);
1807
0
                }
1808
0
            }
1809
0
        }
1810
0
    }
1811
1812
0
    std::sort(sizes.begin(), sizes.end());
1813
0
    return sizes;
1814
0
}
1815
1816
1817
/*!
1818
    Returns a list of standard font sizes.
1819
1820
    \sa smoothSizes(), pointSizes()
1821
*/
1822
QList<int> QFontDatabase::standardSizes()
1823
0
{
1824
0
    return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->standardSizes();
1825
0
}
1826
1827
1828
/*!
1829
    Returns \c true if the font that has family \a family and style \a
1830
    style is italic; otherwise returns \c false.
1831
1832
    \sa weight(), bold()
1833
*/
1834
bool QFontDatabase::italic(const QString &family, const QString &style)
1835
0
{
1836
0
    QString familyName, foundryName;
1837
0
    parseFontName(family, foundryName, familyName);
1838
1839
0
    QMutexLocker locker(fontDatabaseMutex());
1840
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1841
1842
0
    QtFontFoundry allStyles(foundryName);
1843
0
    QtFontFamily *f = d->family(familyName);
1844
0
    if (!f) return false;
1845
1846
0
    for (int j = 0; j < f->count; j++) {
1847
0
        QtFontFoundry *foundry = f->foundries[j];
1848
0
        if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1849
0
            for (int k = 0; k < foundry->count; k++) {
1850
0
                allStyles.style(foundry->styles[k]->key,
1851
0
                                foundry->styles[k]->styleName,
1852
0
                                QtFontFoundry::AddWhenMissing);
1853
0
            }
1854
0
        }
1855
0
    }
1856
1857
0
    QtFontStyle::Key styleKey(style);
1858
0
    QtFontStyle *s = allStyles.style(styleKey, style);
1859
0
    return s && s->key.style == QFont::StyleItalic;
1860
0
}
1861
1862
1863
/*!
1864
    Returns \c true if the font that has family \a family and style \a
1865
    style is bold; otherwise returns \c false.
1866
1867
    \sa italic(), weight()
1868
*/
1869
bool QFontDatabase::bold(const QString &family,
1870
                          const QString &style)
1871
0
{
1872
0
    QString familyName, foundryName;
1873
0
    parseFontName(family, foundryName, familyName);
1874
1875
0
    QMutexLocker locker(fontDatabaseMutex());
1876
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1877
1878
0
    QtFontFoundry allStyles(foundryName);
1879
0
    QtFontFamily *f = d->family(familyName);
1880
0
    if (!f) return false;
1881
1882
0
    for (int j = 0; j < f->count; j++) {
1883
0
        QtFontFoundry *foundry = f->foundries[j];
1884
0
        if (foundryName.isEmpty() ||
1885
0
            foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1886
0
            for (int k = 0; k < foundry->count; k++) {
1887
0
                allStyles.style(foundry->styles[k]->key,
1888
0
                                foundry->styles[k]->styleName,
1889
0
                                QtFontFoundry::AddWhenMissing);
1890
0
            }
1891
0
        }
1892
0
    }
1893
1894
0
    QtFontStyle::Key styleKey(style);
1895
0
    QtFontStyle *s = allStyles.style(styleKey, style);
1896
0
    return s && s->key.weight >= QFont::Bold;
1897
0
}
1898
1899
1900
/*!
1901
    Returns the weight of the font that has family \a family and style
1902
    \a style. If there is no such family and style combination,
1903
    returns -1.
1904
1905
    \sa italic(), bold()
1906
*/
1907
int QFontDatabase::weight(const QString &family,
1908
                           const QString &style)
1909
0
{
1910
0
    QString familyName, foundryName;
1911
0
    parseFontName(family, foundryName, familyName);
1912
1913
0
    QMutexLocker locker(fontDatabaseMutex());
1914
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1915
1916
0
    QtFontFoundry allStyles(foundryName);
1917
0
    QtFontFamily *f = d->family(familyName);
1918
0
    if (!f) return -1;
1919
1920
0
    for (int j = 0; j < f->count; j++) {
1921
0
        QtFontFoundry *foundry = f->foundries[j];
1922
0
        if (foundryName.isEmpty() ||
1923
0
            foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1924
0
            for (int k = 0; k < foundry->count; k++) {
1925
0
                allStyles.style(foundry->styles[k]->key,
1926
0
                                foundry->styles[k]->styleName,
1927
0
                                QtFontFoundry::AddWhenMissing);
1928
0
            }
1929
0
        }
1930
0
    }
1931
1932
0
    QtFontStyle::Key styleKey(style);
1933
0
    QtFontStyle *s = allStyles.style(styleKey, style);
1934
0
    return s ? s->key.weight : -1;
1935
0
}
1936
1937
1938
/*! \internal */
1939
bool QFontDatabase::hasFamily(const QString &family)
1940
0
{
1941
0
    QString parsedFamily, foundry;
1942
0
    parseFontName(family, foundry, parsedFamily);
1943
0
    const QString familyAlias = QFontDatabasePrivate::resolveFontFamilyAlias(parsedFamily);
1944
1945
0
    QMutexLocker locker(fontDatabaseMutex());
1946
0
    QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
1947
1948
0
    for (int i = 0; i < d->count; i++) {
1949
0
        QtFontFamily *f = d->families[i];
1950
0
        if (f->populated && f->count == 0)
1951
0
            continue;
1952
0
        if (familyAlias.compare(f->name, Qt::CaseInsensitive) == 0)
1953
0
            return true;
1954
0
    }
1955
1956
0
    return false;
1957
0
}
1958
1959
1960
/*!
1961
    \since 5.5
1962
1963
    Returns \c true if and only if the \a family font family is private.
1964
1965
    This happens, for instance, on \macos and iOS, where the system UI fonts are not
1966
    accessible to the user. For completeness, QFontDatabase::families() returns all
1967
    font families, including the private ones. You should use this function if you
1968
    are developing a font selection control in order to keep private fonts hidden.
1969
1970
    \sa families()
1971
*/
1972
bool QFontDatabase::isPrivateFamily(const QString &family)
1973
0
{
1974
0
    return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->isPrivateFontFamily(family);
1975
0
}
1976
1977
1978
/*!
1979
    Returns the names the \a writingSystem (e.g. for displaying to the
1980
    user in a dialog).
1981
*/
1982
QString QFontDatabase::writingSystemName(WritingSystem writingSystem)
1983
0
{
1984
0
    const char *name = nullptr;
1985
0
    switch (writingSystem) {
1986
0
    case Any:
1987
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Any");
1988
0
        break;
1989
0
    case Latin:
1990
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Latin");
1991
0
        break;
1992
0
    case Greek:
1993
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Greek");
1994
0
        break;
1995
0
    case Cyrillic:
1996
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Cyrillic");
1997
0
        break;
1998
0
    case Armenian:
1999
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Armenian");
2000
0
        break;
2001
0
    case Hebrew:
2002
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Hebrew");
2003
0
        break;
2004
0
    case Arabic:
2005
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Arabic");
2006
0
        break;
2007
0
    case Syriac:
2008
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Syriac");
2009
0
        break;
2010
0
    case Thaana:
2011
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Thaana");
2012
0
        break;
2013
0
    case Devanagari:
2014
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Devanagari");
2015
0
        break;
2016
0
    case Bengali:
2017
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Bengali");
2018
0
        break;
2019
0
    case Gurmukhi:
2020
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Gurmukhi");
2021
0
        break;
2022
0
    case Gujarati:
2023
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Gujarati");
2024
0
        break;
2025
0
    case Oriya:
2026
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Oriya");
2027
0
        break;
2028
0
    case Tamil:
2029
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Tamil");
2030
0
        break;
2031
0
    case Telugu:
2032
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Telugu");
2033
0
        break;
2034
0
    case Kannada:
2035
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Kannada");
2036
0
        break;
2037
0
    case Malayalam:
2038
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Malayalam");
2039
0
        break;
2040
0
    case Sinhala:
2041
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Sinhala");
2042
0
        break;
2043
0
    case Thai:
2044
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Thai");
2045
0
        break;
2046
0
    case Lao:
2047
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Lao");
2048
0
        break;
2049
0
    case Tibetan:
2050
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Tibetan");
2051
0
        break;
2052
0
    case Myanmar:
2053
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Myanmar");
2054
0
        break;
2055
0
    case Georgian:
2056
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Georgian");
2057
0
        break;
2058
0
    case Khmer:
2059
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Khmer");
2060
0
        break;
2061
0
    case SimplifiedChinese:
2062
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Simplified Chinese");
2063
0
        break;
2064
0
    case TraditionalChinese:
2065
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Traditional Chinese");
2066
0
        break;
2067
0
    case Japanese:
2068
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Japanese");
2069
0
        break;
2070
0
    case Korean:
2071
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Korean");
2072
0
        break;
2073
0
    case Vietnamese:
2074
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Vietnamese");
2075
0
        break;
2076
0
    case Symbol:
2077
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Symbol");
2078
0
        break;
2079
0
    case Ogham:
2080
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Ogham");
2081
0
        break;
2082
0
    case Runic:
2083
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "Runic");
2084
0
        break;
2085
0
    case Nko:
2086
0
        name = QT_TRANSLATE_NOOP("QFontDatabase", "N'Ko");
2087
0
        break;
2088
0
    default:
2089
0
        Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter");
2090
0
        break;
2091
0
    }
2092
0
    return QCoreApplication::translate("QFontDatabase", name);
2093
0
}
2094
2095
/*!
2096
    Returns a string with sample characters from \a writingSystem.
2097
*/
2098
QString QFontDatabase::writingSystemSample(WritingSystem writingSystem)
2099
0
{
2100
0
    return [&]() -> QStringView {
2101
0
        switch (writingSystem) {
2102
0
        case QFontDatabase::Any:
2103
0
        case QFontDatabase::Symbol:
2104
            // show only ascii characters
2105
0
            return u"AaBbzZ";
2106
0
        case QFontDatabase::Latin:
2107
            // This is cheating... we only show latin-1 characters so that we don't
2108
            // end up loading lots of fonts - at least on X11...
2109
0
            return u"Aa\x00C3\x00E1Zz";
2110
0
        case QFontDatabase::Greek:
2111
0
            return u"\x0393\x03B1\x03A9\x03C9";
2112
0
        case QFontDatabase::Cyrillic:
2113
0
            return u"\x0414\x0434\x0436\x044f";
2114
0
        case QFontDatabase::Armenian:
2115
0
            return u"\x053f\x054f\x056f\x057f";
2116
0
        case QFontDatabase::Hebrew:
2117
0
            return u"\x05D0\x05D1\x05D2\x05D3";
2118
0
        case QFontDatabase::Arabic:
2119
0
            return u"\x0623\x0628\x062C\x062F\x064A\x0629\x0020\x0639\x0631\x0628\x064A\x0629";
2120
0
        case QFontDatabase::Syriac:
2121
0
            return u"\x0715\x0725\x0716\x0726";
2122
0
        case QFontDatabase::Thaana:
2123
0
            return u"\x0784\x0794\x078c\x078d";
2124
0
        case QFontDatabase::Devanagari:
2125
0
            return u"\x0905\x0915\x0925\x0935";
2126
0
        case QFontDatabase::Bengali:
2127
0
            return u"\x0986\x0996\x09a6\x09b6";
2128
0
        case QFontDatabase::Gurmukhi:
2129
0
            return u"\x0a05\x0a15\x0a25\x0a35";
2130
0
        case QFontDatabase::Gujarati:
2131
0
            return u"\x0a85\x0a95\x0aa5\x0ab5";
2132
0
        case QFontDatabase::Oriya:
2133
0
            return u"\x0b06\x0b16\x0b2b\x0b36";
2134
0
        case QFontDatabase::Tamil:
2135
0
            return u"\x0b89\x0b99\x0ba9\x0bb9";
2136
0
        case QFontDatabase::Telugu:
2137
0
            return u"\x0c05\x0c15\x0c25\x0c35";
2138
0
        case QFontDatabase::Kannada:
2139
0
            return u"\x0c85\x0c95\x0ca5\x0cb5";
2140
0
        case QFontDatabase::Malayalam:
2141
0
            return u"\x0d05\x0d15\x0d25\x0d35";
2142
0
        case QFontDatabase::Sinhala:
2143
0
            return u"\x0d90\x0da0\x0db0\x0dc0";
2144
0
        case QFontDatabase::Thai:
2145
0
            return u"\x0e02\x0e12\x0e22\x0e32";
2146
0
        case QFontDatabase::Lao:
2147
0
            return u"\x0e8d\x0e9d\x0ead\x0ebd";
2148
0
        case QFontDatabase::Tibetan:
2149
0
            return u"\x0f00\x0f01\x0f02\x0f03";
2150
0
        case QFontDatabase::Myanmar:
2151
0
            return u"\x1000\x1001\x1002\x1003";
2152
0
        case QFontDatabase::Georgian:
2153
0
            return u"\x10a0\x10b0\x10c0\x10d0";
2154
0
        case QFontDatabase::Khmer:
2155
0
            return u"\x1780\x1790\x17b0\x17c0";
2156
0
        case QFontDatabase::SimplifiedChinese:
2157
0
            return u"\x4e2d\x6587\x8303\x4f8b";
2158
0
        case QFontDatabase::TraditionalChinese:
2159
0
            return u"\x4e2d\x6587\x7bc4\x4f8b";
2160
0
        case QFontDatabase::Japanese:
2161
0
            return u"\x30b5\x30f3\x30d7\x30eb\x3067\x3059";
2162
0
        case QFontDatabase::Korean:
2163
0
            return u"\xac00\xac11\xac1a\xac2f";
2164
0
        case QFontDatabase::Vietnamese:
2165
0
            return u"\x1ED7\x1ED9\x1ED1\x1ED3";
2166
0
        case QFontDatabase::Ogham:
2167
0
            return u"\x1681\x1682\x1683\x1684";
2168
0
        case QFontDatabase::Runic:
2169
0
            return u"\x16a0\x16a1\x16a2\x16a3";
2170
0
        case QFontDatabase::Nko:
2171
0
            return u"\x7ca\x7cb\x7cc\x7cd";
2172
0
        default:
2173
0
            return nullptr;
2174
0
        }
2175
0
    }().toString();
2176
0
}
2177
2178
void QFontDatabasePrivate::parseFontName(const QString &name, QString &foundry, QString &family)
2179
0
{
2180
0
    QT_PREPEND_NAMESPACE(parseFontName)(name, foundry, family);
2181
0
}
2182
2183
// used from qfontengine_ft.cpp
2184
Q_GUI_EXPORT QByteArray qt_fontdata_from_index(int index)
2185
0
{
2186
0
    QMutexLocker locker(fontDatabaseMutex());
2187
0
    return QFontDatabasePrivate::instance()->applicationFonts.value(index).data;
2188
0
}
2189
2190
int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &fileName)
2191
0
{
2192
0
    QFontDatabasePrivate::ApplicationFont font;
2193
0
    font.data = fontData;
2194
0
    font.fileName = fileName;
2195
2196
0
    Q_TRACE(QFontDatabasePrivate_addAppFont, fileName);
2197
2198
0
    int i;
2199
0
    for (i = 0; i < applicationFonts.size(); ++i)
2200
0
        if (applicationFonts.at(i).isNull())
2201
0
            break;
2202
0
    if (i >= applicationFonts.size()) {
2203
0
        applicationFonts.append(ApplicationFont());
2204
0
        i = applicationFonts.size() - 1;
2205
0
    }
2206
2207
0
    if (font.fileName.isEmpty() && !fontData.isEmpty())
2208
0
        font.fileName = ":qmemoryfonts/"_L1 + QString::number(i);
2209
2210
0
    auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
2211
0
    platformFontDatabase->addApplicationFont(font.data, font.fileName, &font);
2212
0
    if (font.properties.isEmpty())
2213
0
        return -1;
2214
2215
0
    applicationFonts[i] = font;
2216
2217
    // The font cache may have cached lookups for the font that was now
2218
    // loaded, so it has to be flushed.
2219
0
    QFontCache::instance()->clear();
2220
2221
0
    fallbacksCache.clear();
2222
2223
0
    emit qApp->fontDatabaseChanged();
2224
2225
0
    return i;
2226
0
}
2227
2228
bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
2229
0
{
2230
0
    for (int i = 0; i < applicationFonts.size(); ++i)
2231
0
        if (applicationFonts.at(i).fileName == fileName)
2232
0
            return true;
2233
0
    return false;
2234
0
}
2235
2236
void QFontDatabasePrivate::setApplicationFallbackFontFamilies(ExtendedScript script, const QStringList &familyNames)
2237
0
{
2238
0
    applicationFallbackFontFamiliesHash[script] = familyNames;
2239
2240
0
    QFontCache::instance()->clear();
2241
0
    fallbacksCache.clear();
2242
0
}
2243
2244
QStringList QFontDatabasePrivate::applicationFallbackFontFamilies(ExtendedScript script)
2245
0
{
2246
0
    return applicationFallbackFontFamiliesHash.value(script);
2247
0
}
2248
2249
bool QFontDatabasePrivate::removeApplicationFallbackFontFamily(ExtendedScript script, const QString &familyName)
2250
0
{
2251
0
    auto it = applicationFallbackFontFamiliesHash.find(script);
2252
0
    if (it != applicationFallbackFontFamiliesHash.end()) {
2253
0
        if (it->removeAll(familyName) > 0) {
2254
0
            if (it->isEmpty())
2255
0
                it = applicationFallbackFontFamiliesHash.erase(it);
2256
0
            QFontCache::instance()->clear();
2257
0
            fallbacksCache.clear();
2258
0
            return true;
2259
0
        }
2260
0
    }
2261
2262
0
    return false;
2263
0
}
2264
2265
void QFontDatabasePrivate::addApplicationFallbackFontFamily(ExtendedScript script, const QString &familyName)
2266
0
{
2267
0
    auto it = applicationFallbackFontFamiliesHash.find(script);
2268
0
    if (it == applicationFallbackFontFamiliesHash.end())
2269
0
        it = applicationFallbackFontFamiliesHash.insert(script, QStringList{});
2270
2271
0
    it->prepend(familyName);
2272
2273
0
    QFontCache::instance()->clear();
2274
0
    fallbacksCache.clear();
2275
0
}
2276
2277
2278
/*!
2279
    \since 4.2
2280
2281
    Loads the font from the file specified by \a fileName and makes it available to
2282
    the application. An ID is returned that can be used to remove the font again
2283
    with removeApplicationFont() or to retrieve the list of family names contained
2284
    in the font.
2285
2286
//! [add-application-font-doc]
2287
    The function returns -1 if the font could not be loaded.
2288
2289
    Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
2290
    supported.
2291
//! [add-application-font-doc]
2292
2293
    \sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
2294
*/
2295
int QFontDatabase::addApplicationFont(const QString &fileName)
2296
0
{
2297
0
    QByteArray data;
2298
0
    if (!QFileInfo(fileName).isNativePath()) {
2299
0
        QFile f(fileName);
2300
0
        if (!f.open(QIODevice::ReadOnly))
2301
0
            return -1;
2302
2303
0
        Q_TRACE(QFontDatabase_addApplicationFont, fileName);
2304
2305
0
        data = f.readAll();
2306
0
    }
2307
0
    QMutexLocker locker(fontDatabaseMutex());
2308
0
    return QFontDatabasePrivate::instance()->addAppFont(data, fileName);
2309
0
}
2310
2311
/*!
2312
    \since 4.2
2313
2314
    Loads the font from binary data specified by \a fontData and makes it available to
2315
    the application. An ID is returned that can be used to remove the font again
2316
    with removeApplicationFont() or to retrieve the list of family names contained
2317
    in the font.
2318
2319
    \include qfontdatabase.cpp add-application-font-doc
2320
2321
    \sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
2322
*/
2323
int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData)
2324
0
{
2325
0
    QMutexLocker locker(fontDatabaseMutex());
2326
0
    return QFontDatabasePrivate::instance()->addAppFont(fontData, QString() /* fileName */);
2327
0
}
2328
2329
/*!
2330
    \since 4.2
2331
2332
    Returns a list of font families for the given application font identified by
2333
    \a id.
2334
2335
    \sa addApplicationFont(), addApplicationFontFromData()
2336
*/
2337
QStringList QFontDatabase::applicationFontFamilies(int id)
2338
0
{
2339
0
    QMutexLocker locker(fontDatabaseMutex());
2340
0
    auto *d = QFontDatabasePrivate::instance();
2341
2342
0
    QStringList ret;
2343
0
    ret.reserve(d->applicationFonts.value(id).properties.size());
2344
2345
0
    for (const auto &properties : d->applicationFonts.value(id).properties)
2346
0
        ret.append(properties.familyName);
2347
2348
0
    return ret;
2349
0
}
2350
2351
/*!
2352
    \since 5.2
2353
2354
    Returns the most adequate font for a given \a type case for proper integration
2355
    with the system's look and feel.
2356
2357
    \sa QGuiApplication::font()
2358
*/
2359
2360
QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type)
2361
0
{
2362
0
    const QFont *font = nullptr;
2363
0
    if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
2364
0
        switch (type) {
2365
0
            case GeneralFont:
2366
0
                font = theme->font(QPlatformTheme::SystemFont);
2367
0
                break;
2368
0
            case FixedFont:
2369
0
                font = theme->font(QPlatformTheme::FixedFont);
2370
0
                break;
2371
0
            case TitleFont:
2372
0
                font = theme->font(QPlatformTheme::TitleBarFont);
2373
0
                break;
2374
0
            case SmallestReadableFont:
2375
0
                font = theme->font(QPlatformTheme::MiniFont);
2376
0
                break;
2377
0
        }
2378
0
    }
2379
2380
0
    if (font)
2381
0
        return *font;
2382
0
    else if (QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration())
2383
0
        return integration->fontDatabase()->defaultFont();
2384
0
    else
2385
0
        return QFont();
2386
0
}
2387
2388
/*!
2389
    \fn bool QFontDatabase::removeApplicationFont(int id)
2390
    \since 4.2
2391
2392
    Removes the previously loaded application font identified by \a
2393
    id. Returns \c true if unloading of the font succeeded; otherwise
2394
    returns \c false.
2395
2396
    \sa removeAllApplicationFonts(), addApplicationFont(),
2397
        addApplicationFontFromData()
2398
*/
2399
bool QFontDatabase::removeApplicationFont(int handle)
2400
0
{
2401
0
    QMutexLocker locker(fontDatabaseMutex());
2402
2403
0
    auto *db = QFontDatabasePrivate::instance();
2404
0
    if (handle < 0 || handle >= db->applicationFonts.size())
2405
0
        return false;
2406
2407
0
    db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
2408
2409
0
    db->invalidate();
2410
0
    return true;
2411
0
}
2412
2413
/*!
2414
    \fn bool QFontDatabase::removeAllApplicationFonts()
2415
    \since 4.2
2416
2417
    Removes all application-local fonts previously added using addApplicationFont()
2418
    and addApplicationFontFromData().
2419
2420
    Returns \c true if unloading of the fonts succeeded; otherwise
2421
    returns \c false.
2422
2423
    \sa removeApplicationFont(), addApplicationFont(), addApplicationFontFromData()
2424
*/
2425
bool QFontDatabase::removeAllApplicationFonts()
2426
0
{
2427
0
    QMutexLocker locker(fontDatabaseMutex());
2428
2429
0
    auto *db = QFontDatabasePrivate::instance();
2430
0
    if (!db || db->applicationFonts.isEmpty())
2431
0
        return false;
2432
2433
0
    db->applicationFonts.clear();
2434
0
    db->invalidate();
2435
0
    return true;
2436
0
}
2437
2438
/*!
2439
    \since 6.8
2440
2441
    Adds \a familyName as an application-defined fallback font for \a script.
2442
2443
    When Qt encounters characters that are not supported by the selected font, it will search
2444
    through a list of fallback fonts to find a match for them. This ensures that combining multiple
2445
    scripts in a single string is possible, even if the main font does not support them.
2446
2447
    The list of fallback fonts is selected based on the script of the string as well as other
2448
    conditions, such as system language.
2449
2450
    While the system fallback list is usually sufficient, there are cases where it is useful
2451
    to override the default behavior. One such case is for using application fonts as fallback to
2452
    ensure cross-platform consistency.
2453
2454
    In another case the application may be written in a script with regional differences and want
2455
    to run it untranslated in multiple regions. In this case, it might be useful to override the
2456
    local region's fallback with one that matches the language of the application.
2457
2458
    By passing \a familyName to addApplicationFallbackFontFamily(), this will become the preferred
2459
    family when matching missing characters from \a script. The \a script must be a valid script
2460
    (\c QChar::Script_Latin or higher). When adding multiple fonts for the same script, they will
2461
    be prioritized in reverse order, so that the last family added will be checked first and so
2462
    on.
2463
2464
    \note Qt's font matching algorithm considers \c{QChar::Script_Common} (undetermined script)
2465
    and \c{QChar::Script_Latin} the same. Adding a fallback for either of these will also apply
2466
    to the other.
2467
2468
    \sa setApplicationFallbackFontFamilies(), removeApplicationFallbackFontFamily(), applicationFallbackFontFamilies()
2469
*/
2470
void QFontDatabase::addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
2471
0
{
2472
0
    QMutexLocker locker(fontDatabaseMutex());
2473
2474
0
    if (script < QChar::Script_Common || script >= QChar::ScriptCount) {
2475
0
        qCWarning(lcFontDb) << "Invalid script passed to addApplicationFallbackFontFamily:" << script;
2476
0
        return;
2477
0
    }
2478
2479
0
    if (script == QChar::Script_Latin)
2480
0
        script = QChar::Script_Common;
2481
2482
0
    auto *db = QFontDatabasePrivate::instance();
2483
0
    db->addApplicationFallbackFontFamily(QFontDatabasePrivate::ExtendedScript(script), familyName);
2484
0
}
2485
2486
/*!
2487
    \since 6.8
2488
2489
    Removes \a familyName from the list of application-defined fallback fonts for \a script,
2490
    provided that it has previously been added with \l{addApplicationFallbackFontFamily()}.
2491
2492
    Returns true if the family name was in the list and false if it was not.
2493
2494
    \sa addApplicationFallbackFontFamily(), setApplicationFallbackFontFamilies(), applicationFallbackFontFamilies()
2495
*/
2496
bool QFontDatabase::removeApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
2497
0
{
2498
0
    QMutexLocker locker(fontDatabaseMutex());
2499
2500
0
    if (script < QChar::Script_Common || script >= QChar::ScriptCount) {
2501
0
        qCWarning(lcFontDb) << "Invalid script passed to removeApplicationFallbackFontFamily:" << script;
2502
0
        return false;
2503
0
    }
2504
2505
0
    if (script == QChar::Script_Latin)
2506
0
        script = QChar::Script_Common;
2507
2508
0
    auto *db = QFontDatabasePrivate::instance();
2509
0
    return db->removeApplicationFallbackFontFamily(QFontDatabasePrivate::ExtendedScript(script),
2510
0
                                                   familyName);
2511
0
}
2512
2513
/*!
2514
    \since 6.8
2515
2516
    Sets the list of application-defined fallback fonts for \a script to \a familyNames.
2517
2518
    When Qt encounters a character in \a script which is not supported by the current font, it will
2519
    check the families in \a familyNames, in order from first to last, until it finds a match. See
2520
    \l{addApplicationFallbackFontFamily()} for more details.
2521
2522
    This function overwrites the current list of application-defined fallback fonts for \a script.
2523
2524
    \sa addApplicationFallbackFontFamily(), removeApplicationFallbackFontFamily(), applicationFallbackFontFamilies()
2525
*/
2526
void QFontDatabase::setApplicationFallbackFontFamilies(QChar::Script script, const QStringList &familyNames)
2527
0
{
2528
0
    QMutexLocker locker(fontDatabaseMutex());
2529
2530
0
    if (script < QChar::Script_Common || script >= QChar::ScriptCount) {
2531
0
        qCWarning(lcFontDb) << "Invalid script passed to setApplicationFallbackFontFamilies:" << script;
2532
0
        return;
2533
0
    }
2534
2535
0
    if (script == QChar::Script_Latin)
2536
0
        script = QChar::Script_Common;
2537
2538
0
    auto *db = QFontDatabasePrivate::instance();
2539
0
    db->setApplicationFallbackFontFamilies(QFontDatabasePrivate::ExtendedScript(script),
2540
0
                                           familyNames);
2541
0
}
2542
2543
/*!
2544
    \since 6.8
2545
2546
    Returns the list of application-defined fallback font families previously added for \a script
2547
    by the \l{addApplicationFallbackFontFamily()} function.
2548
2549
    \sa setApplicationFallbackFontFamilies(), addApplicationFallbackFontFamily(), removeApplicationFallbackFontFamily()
2550
*/
2551
QStringList QFontDatabase::applicationFallbackFontFamilies(QChar::Script script)
2552
0
{
2553
0
    QMutexLocker locker(fontDatabaseMutex());
2554
2555
0
    if (script >= QChar::ScriptCount) {
2556
0
        qCWarning(lcFontDb) << "Invalid script passed to applicationFallbackFontFamilies:" << script;
2557
0
        return QStringList{};
2558
0
    }
2559
2560
0
    if (script == QChar::Script_Latin)
2561
0
        script = QChar::Script_Common;
2562
2563
0
    auto *db = QFontDatabasePrivate::instance();
2564
0
    return db->applicationFallbackFontFamilies(QFontDatabasePrivate::ExtendedScript(script));
2565
0
}
2566
2567
/*!
2568
    \since 6.9
2569
2570
    Adds \a familyName as an application-defined emoji font.
2571
2572
    For displaying multi-color emojis or emoji sequences, Qt will by default prefer the system
2573
    default emoji font. Sometimes the application may want to override the default, either to
2574
    achieve a specific visual style or to show emojis that are not supported by the system.
2575
2576
    \sa removeApplicationEmojiFontFamily, setApplicationEmojiFontFamilies(), applicationEmojiFontFamilies(), addApplicationFallbackFontFamily()
2577
*/
2578
void QFontDatabase::addApplicationEmojiFontFamily(const QString &familyName)
2579
0
{
2580
0
    QMutexLocker locker(fontDatabaseMutex());
2581
0
    auto *db = QFontDatabasePrivate::instance();
2582
0
    db->addApplicationFallbackFontFamily(QFontDatabasePrivate::Script_Emoji, familyName);
2583
0
}
2584
2585
/*!
2586
    \since 6.9
2587
2588
    Removes \a familyName from the list of application-defined emoji fonts,
2589
    provided that it has previously been added with \l{addApplicationEmojiFontFamily()}.
2590
2591
    Returns true if the family name was in the list and false if it was not.
2592
2593
    \sa addApplicationEmojiFontFamily(), setApplicationEmojiFontFamilies(), applicationEmojiFontFamilies(), removeApplicationFallbackFontFamily()
2594
*/
2595
bool QFontDatabase::removeApplicationEmojiFontFamily(const QString &familyName)
2596
0
{
2597
0
    QMutexLocker locker(fontDatabaseMutex());
2598
0
    auto *db = QFontDatabasePrivate::instance();
2599
0
    return db->removeApplicationFallbackFontFamily(QFontDatabasePrivate::Script_Emoji,
2600
0
                                                   familyName);
2601
0
}
2602
2603
/*!
2604
    \since 6.9
2605
2606
    Sets the list of application-defined emoji fonts to \a familyNames.
2607
2608
    \sa addApplicationEmojiFontFamily(), removeApplicationEmojiFontFamily(), applicationEmojiFontFamilies(), setApplicationFallbackFontFamilies()
2609
*/
2610
void QFontDatabase::setApplicationEmojiFontFamilies(const QStringList &familyNames)
2611
0
{
2612
0
    QMutexLocker locker(fontDatabaseMutex());
2613
0
    auto *db = QFontDatabasePrivate::instance();
2614
0
    db->setApplicationFallbackFontFamilies(QFontDatabasePrivate::Script_Emoji,
2615
0
                                           familyNames);
2616
0
}
2617
2618
/*!
2619
    \since 6.9
2620
2621
    Returns the list of application-defined emoji font families.
2622
2623
    \sa addApplicationEmojiFontFamily(), removeApplicationEmojiFontFamily(), setApplicationEmojiFontFamilies(), applicationFallbackFontFamilies()
2624
*/
2625
QStringList QFontDatabase::applicationEmojiFontFamilies()
2626
0
{
2627
0
    QMutexLocker locker(fontDatabaseMutex());
2628
0
    auto *db = QFontDatabasePrivate::instance();
2629
0
    return db->applicationFallbackFontFamilies(QFontDatabasePrivate::Script_Emoji);
2630
0
}
2631
2632
/*!
2633
    \internal
2634
*/
2635
QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
2636
                                            int script,
2637
                                            bool preferScriptOverFamily)
2638
0
{
2639
0
    QMutexLocker locker(fontDatabaseMutex());
2640
0
    ensureFontDatabase();
2641
2642
0
    QFontEngine *engine;
2643
2644
#ifdef Q_OS_WIN
2645
    const QFontDef request = static_cast<QWindowsFontDatabaseBase *>(
2646
                                     QGuiApplicationPrivate::platformIntegration()->fontDatabase())
2647
                                     ->sanitizeRequest(req);
2648
#else
2649
0
    const QFontDef &request = req;
2650
0
#endif
2651
2652
#if defined(QT_BUILD_INTERNAL)
2653
    // For testing purpose only, emulates an exact-matching monospace font
2654
    if (qt_enable_test_font && request.families.first() == "__Qt__Box__Engine__"_L1) {
2655
        engine = new QTestFontEngine(request.pixelSize);
2656
        engine->fontDef = request;
2657
        return engine;
2658
    }
2659
#endif
2660
2661
0
    QFontCache *fontCache = QFontCache::instance();
2662
2663
    // Until we specifically asked not to, try looking for Multi font engine
2664
    // first, the last '1' indicates that we want Multi font engine instead
2665
    // of single ones
2666
0
    bool multi = !(request.styleStrategy & QFont::NoFontMerging);
2667
0
    QFontCache::Key key(request, script, multi ? 1 : 0);
2668
0
    engine = fontCache->findEngine(key);
2669
0
    if (engine) {
2670
0
        qCDebug(lcFontMatch, "Cache hit level 1");
2671
0
        return engine;
2672
0
    }
2673
2674
0
    if (request.pixelSize > 0xffff) {
2675
        // Stop absurd requests reaching the engines; pixel size is assumed to fit ushort
2676
0
        qCDebug(lcFontMatch, "Rejecting request for pixel size %g2, returning box engine", double(request.pixelSize));
2677
0
        return new QFontEngineBox(32); // not request.pixelSize, to avoid overflow/DOS
2678
0
    }
2679
2680
0
    QString family_name, foundry_name;
2681
0
    const QString requestFamily = request.families.at(0);
2682
0
    parseFontName(requestFamily, foundry_name, family_name);
2683
0
    QtFontDesc desc;
2684
0
    QList<int> blackListed;
2685
0
    unsigned int score = UINT_MAX;
2686
2687
    // 1.
2688
    // We start by looking up the family name and finding the best style/foundry. For multi fonts
2689
    // we always want the requested font to be on top, even if it does not support the selected
2690
    // script, since the fallback mechanism will handle this later. For NoFontMerging fonts, we pass
2691
    // in the script in order to prefer foundries that support the script. If none is found, we will
2692
    // retry with Script_Common later. Note that Script_Emoji is special. This means the Unicode
2693
    // algorithm has determined that we should use a color font. If the selected font is not
2694
    // a color font, we use the fall back mechanism to find one, since we want to prefer *any* color
2695
    // font over a non-color font in this case.
2696
0
    qCDebug(lcFontMatch, "Family name match pass: Looking for family name '%s'%s", qPrintable(family_name),
2697
0
            script == QFontDatabasePrivate::Script_Emoji ? " (color font required)" : "");
2698
0
    int index = match(multi && script != QFontDatabasePrivate::Script_Emoji ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed, &score);
2699
2700
    // 2.
2701
    // If no font was found or it was not a perfect match, we let the database populate family
2702
    // aliases and try again.
2703
0
    if (score > 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
2704
0
        qCDebug(lcFontMatch, "Alias match pass: Imperfect result and aliases populated, so trying again%s",
2705
0
                script == QFontDatabasePrivate::Script_Emoji ? " (color font required)" : "");
2706
        // We populated family aliases (e.g. localized families), so try again
2707
0
        index = match(multi && script != QFontDatabasePrivate::Script_Emoji ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
2708
0
    }
2709
2710
    // 3.
2711
    // If we do not find a match and NoFontMerging is set, use the requested font even if it does
2712
    // not support the script.
2713
    //
2714
    // (we do this at the end to prefer foundries that support the script if they exist)
2715
0
    if (index < 0 && !multi && !preferScriptOverFamily) {
2716
0
        qCDebug(lcFontMatch, "NoFontMerging pass: Font not found with requested script, but we try to load it anyway");
2717
0
        index = match(QChar::Script_Common, request, family_name, foundry_name, &desc, blackListed);
2718
0
    }
2719
2720
0
    if (index >= 0) {
2721
0
        QFontDef fontDef = request;
2722
        // Don't pass empty family names to the platform font database, since it will then invoke its own matching
2723
        // and we will be out of sync with the matched font.
2724
0
        if (fontDef.families.isEmpty())
2725
0
            fontDef.families = QStringList(desc.family->name);
2726
2727
0
        engine = loadEngine(script, fontDef, desc.family, desc.foundry, desc.style, desc.size);
2728
2729
0
        if (engine) {
2730
0
            initFontDef(desc, request, &engine->fontDef, multi);
2731
0
        } else {
2732
0
            qCDebug(lcFontMatch, "Failed to create font engine for font '%s'. Blacklisting %d",
2733
0
                    qPrintable(desc.family->name), index);
2734
0
            blackListed.append(index);
2735
0
        }
2736
0
    } else {
2737
0
        qCDebug(lcFontMatch, "  NO MATCH FOUND\n");
2738
0
    }
2739
2740
    // 4.
2741
    // If no font matching the script + family exists, we go via the fallback mechanism. This
2742
    // happens when the family does not exist or if we want a color font and the requested font
2743
    // is not.
2744
0
    if (!engine) {
2745
0
        if (!requestFamily.isEmpty()) {
2746
0
            qCDebug(lcFontMatch, "Fallbacks pass: Looking for a fallback matching script %d", script);
2747
0
            QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
2748
0
            if (styleHint == QFont::AnyStyle && request.fixedPitch)
2749
0
                styleHint = QFont::TypeWriter;
2750
2751
0
            QStringList fallbacks = request.fallBackFamilies
2752
0
                                  + fallbacksForFamily(requestFamily,
2753
0
                                                       QFont::Style(request.style),
2754
0
                                                       styleHint,
2755
0
                                                       QFontDatabasePrivate::ExtendedScript(script));
2756
0
            if (script > QChar::Script_Common)
2757
0
                fallbacks += QString(); // Find the first font matching the specified script.
2758
2759
0
            auto findMatchingFallback = [&fallbacks,
2760
0
                                         &index,
2761
0
                                         &multi,
2762
0
                                         &fontCache,
2763
0
                                         &blackListed,
2764
0
                                         &request](int lookupScript, int cacheScript) {
2765
0
                QFontEngine *engine = nullptr;
2766
0
                for (int i = 0; !engine && i < fallbacks.size(); i++) {
2767
0
                    QFontDef def = request;
2768
2769
0
                    def.families = QStringList(fallbacks.at(i));
2770
0
                    QFontCache::Key key(def, cacheScript, multi ? 1 : 0);
2771
0
                    engine = fontCache->findEngine(key);
2772
0
                    if (!engine) {
2773
0
                        QtFontDesc desc;
2774
0
                        do {
2775
0
                            index = match(lookupScript,
2776
0
                                          def,
2777
0
                                          def.families.constFirst(),
2778
0
                                          ""_L1,
2779
0
                                          &desc,
2780
0
                                          blackListed);
2781
2782
0
                            if (index >= 0) {
2783
0
                                QFontDef loadDef = def;
2784
0
                                if (loadDef.families.isEmpty())
2785
0
                                    loadDef.families = QStringList(desc.family->name);
2786
0
                                engine = loadEngine(cacheScript,
2787
0
                                                    loadDef,
2788
0
                                                    desc.family,
2789
0
                                                    desc.foundry,
2790
0
                                                    desc.style,
2791
0
                                                    desc.size);
2792
0
                                if (engine) {
2793
0
                                    initFontDef(desc, loadDef, &engine->fontDef, multi);
2794
0
                                } else {
2795
0
                                    qCDebug(lcFontMatch, "Failed to create font engine for fallback %d (%s). Blacklisting %d",
2796
0
                                            i, qPrintable(desc.family->name), index);
2797
0
                                    blackListed.append(index);
2798
0
                                }
2799
0
                            }
2800
0
                        } while (index >= 0 && !engine);
2801
0
                    }
2802
0
                }
2803
2804
0
                return engine;
2805
0
            };
2806
2807
0
            engine = findMatchingFallback(multi && script != QFontDatabasePrivate::Script_Emoji
2808
0
                                          ? QChar::Script_Common
2809
0
                                          : script,
2810
0
                                          script);
2811
2812
            // If we are looking for a color font and there are no color fonts on the system,
2813
            // we will end up here, for one final pass. This is a rare occurrence so we accept
2814
            // and extra pass on the fallbacks for this.
2815
0
            if (!engine && script == QFontDatabasePrivate::Script_Emoji) {
2816
0
                qCDebug(lcFontMatch, "No color fonts found on system. Doing final fallback match.");
2817
2818
                // Since we no longer require color fonts, we need to retry to check if the
2819
                // actual requested font is available as a non-color font.
2820
0
                if (!requestFamily.isEmpty())
2821
0
                    fallbacks.prepend(requestFamily);
2822
0
                engine = findMatchingFallback(QChar::Script_Common, script);
2823
0
            }
2824
0
        }
2825
2826
0
        if (!engine) {
2827
0
            engine = new QFontEngineBox(request.pixelSize);
2828
0
            qCDebug(lcFontMatch, "returning box engine");
2829
0
        }
2830
0
    }
2831
2832
0
    return engine;
2833
0
}
2834
2835
void QFontDatabasePrivate::load(const QFontPrivate *d, int script)
2836
0
{
2837
0
    QFontDef req = d->request;
2838
2839
0
    if (req.pixelSize == -1) {
2840
0
        req.pixelSize = std::floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100;
2841
0
        req.pixelSize = qRound(req.pixelSize);
2842
0
    }
2843
2844
0
    if (req.pointSize < 0 && d->dpi > 0)
2845
0
        req.pointSize = req.pixelSize*72.0/d->dpi;
2846
2847
    // respect the fallback families that might be passed through the request
2848
0
    const QStringList fallBackFamilies = familyList(req);
2849
2850
0
    if (!d->engineData) {
2851
0
        QFontCache *fontCache = QFontCache::instance();
2852
        // look for the requested font in the engine data cache
2853
        // note: fallBackFamilies are not respected in the EngineData cache key;
2854
        //       join them with the primary selection family to avoid cache misses
2855
0
        if (!d->request.families.isEmpty())
2856
0
            req.families = fallBackFamilies;
2857
2858
0
        d->engineData = fontCache->findEngineData(req);
2859
0
        if (!d->engineData) {
2860
            // create a new one
2861
0
            d->engineData = new QFontEngineData;
2862
0
            fontCache->insertEngineData(req, d->engineData);
2863
0
        }
2864
0
        d->engineData->ref.ref();
2865
0
    }
2866
2867
    // the cached engineData could have already loaded the engine we want
2868
0
    if (d->engineData->engines[script])
2869
0
        return;
2870
2871
0
    QFontEngine *fe = nullptr;
2872
2873
0
    Q_TRACE(QFontDatabase_load, req.families.join(QLatin1Char(';')), req.pointSize);
2874
2875
0
    req.fallBackFamilies = fallBackFamilies;
2876
0
    if (!req.fallBackFamilies.isEmpty())
2877
0
        req.families = QStringList(req.fallBackFamilies.takeFirst());
2878
2879
    // list of families to try
2880
0
    QStringList family_list;
2881
2882
0
    if (!req.families.isEmpty()) {
2883
        // Add primary selection
2884
0
        family_list << req.families.at(0);
2885
2886
        // add the default family
2887
0
        const auto families = QGuiApplication::font().families();
2888
0
        if (!families.isEmpty()) {
2889
0
            QString defaultFamily = families.first();
2890
0
            if (! family_list.contains(defaultFamily))
2891
0
                family_list << defaultFamily;
2892
0
        }
2893
2894
0
    }
2895
2896
    // null family means find the first font matching the specified script
2897
0
    family_list << QString();
2898
2899
0
    QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
2900
0
    for (; !fe && it != end; ++it) {
2901
0
        req.families = QStringList(*it);
2902
2903
0
        fe = QFontDatabasePrivate::findFont(req, script);
2904
0
        if (fe) {
2905
0
            if (fe->type() == QFontEngine::Box && !req.families.at(0).isEmpty()) {
2906
0
                if (fe->ref.loadRelaxed() == 0)
2907
0
                    delete fe;
2908
0
                fe = nullptr;
2909
0
            } else {
2910
0
                if (d->dpi > 0)
2911
0
                    fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / d->dpi));
2912
0
            }
2913
0
        }
2914
2915
        // No need to check requested fallback families again
2916
0
        req.fallBackFamilies.clear();
2917
0
    }
2918
2919
0
    Q_ASSERT(fe);
2920
0
    if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
2921
0
        for (int i = 0; i < QFontDatabasePrivate::ScriptCount; ++i) {
2922
0
            if (!d->engineData->engines[i]) {
2923
0
                d->engineData->engines[i] = fe;
2924
0
                fe->ref.ref();
2925
0
            }
2926
0
        }
2927
0
    } else {
2928
0
        d->engineData->engines[script] = fe;
2929
0
        fe->ref.ref();
2930
0
    }
2931
0
}
2932
2933
QString QFontDatabasePrivate::resolveFontFamilyAlias(const QString &family)
2934
0
{
2935
0
    return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
2936
0
}
2937
2938
Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QFontDatabasePrivate::ExtendedScript script,
2939
                                                            const QStringList &families)
2940
0
{
2941
0
    size_t writingSystem = qt_writing_system_for_script(script);
2942
0
    if (script != QFontDatabasePrivate::Script_Emoji
2943
0
                && (writingSystem == QFontDatabase::Any
2944
0
                    || writingSystem >= QFontDatabase::WritingSystemsCount)) {
2945
0
        return families;
2946
0
    }
2947
2948
0
    auto *db = QFontDatabasePrivate::instance();
2949
0
    QMultiMap<uint, QString> supported;
2950
0
    for (int i = 0; i < families.size(); ++i) {
2951
0
        const QString &family = families.at(i);
2952
2953
0
        QtFontFamily *testFamily = nullptr;
2954
0
        for (int x = 0; x < db->count; ++x) {
2955
0
            if (Q_UNLIKELY(matchFamilyName(family, db->families[x]))) {
2956
0
                testFamily = db->families[x];
2957
0
                if (testFamily->ensurePopulated())
2958
0
                    break;
2959
0
            }
2960
0
        }
2961
2962
0
        uint order = i;
2963
0
        if (testFamily == nullptr
2964
0
              || (script == QFontDatabasePrivate::Script_Emoji && !testFamily->colorFont)
2965
0
              || (script != QFontDatabasePrivate::Script_Emoji && !familySupportsWritingSystem(testFamily, writingSystem))) {
2966
0
            order |= 1u << 31;
2967
0
        }
2968
2969
0
        supported.insert(order, family);
2970
0
    }
2971
2972
0
    return supported.values();
2973
0
}
2974
2975
QT_END_NAMESPACE
2976
2977
#include "moc_qfontdatabase.cpp"
2978