Coverage Report

Created: 2026-09-28 08:21

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