Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/text/unix/qfontconfigdatabase.cpp
Line
Count
Source
1
// Copyright (C) 2019 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 "qfontconfigdatabase_p.h"
5
#include "qfontenginemultifontconfig_p.h"
6
7
#include <QtGui/private/qfontengine_ft_p.h>
8
9
#include <QtCore/QList>
10
#include <QtCore/QElapsedTimer>
11
#include <QtCore/QFile>
12
13
#include <qpa/qplatformnativeinterface.h>
14
#include <qpa/qplatformscreen.h>
15
#include <qpa/qplatformintegration.h>
16
#include <qpa/qplatformservices.h>
17
18
#include <QtGui/private/qguiapplication_p.h>
19
20
#include <QtGui/qguiapplication.h>
21
22
#include <QtCore/private/qduplicatetracker_p.h>
23
24
#include <fontconfig/fontconfig.h>
25
#if FC_VERSION >= 20402
26
#include <fontconfig/fcfreetype.h>
27
#endif
28
29
QT_BEGIN_NAMESPACE
30
31
static inline int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, int qtLower, int qtUpper)
32
0
{
33
0
    return qtLower + ((fcweight - fcLower) * (qtUpper - qtLower)) / (fcUpper - fcLower);
34
0
}
35
36
static inline int weightFromFcWeight(int fcweight)
37
0
{
38
    // Font Config uses weights from 0 to 215 (the highest enum value) while QFont ranges from
39
    // 1 to 1000. The spacing between the values for the enums are uneven so a linear mapping from
40
    // Font Config values to Qt would give surprising results.  So, we do a piecewise linear
41
    // mapping.  This ensures that where there is a corresponding enum on both sides (for example
42
    // FC_WEIGHT_DEMIBOLD and QFont::DemiBold) we map one to the other but other values map
43
    // to intermediate Qt weights.
44
45
0
    if (fcweight <= FC_WEIGHT_THIN)
46
0
        return QFont::Thin;
47
0
    if (fcweight <= FC_WEIGHT_ULTRALIGHT)
48
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_THIN, FC_WEIGHT_ULTRALIGHT, QFont::Thin, QFont::ExtraLight);
49
0
    if (fcweight <= FC_WEIGHT_LIGHT)
50
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_ULTRALIGHT, FC_WEIGHT_LIGHT, QFont::ExtraLight, QFont::Light);
51
0
    if (fcweight <= FC_WEIGHT_NORMAL)
52
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_LIGHT, FC_WEIGHT_NORMAL, QFont::Light, QFont::Normal);
53
0
    if (fcweight <= FC_WEIGHT_MEDIUM)
54
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_NORMAL, FC_WEIGHT_MEDIUM, QFont::Normal, QFont::Medium);
55
0
    if (fcweight <= FC_WEIGHT_DEMIBOLD)
56
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_MEDIUM, FC_WEIGHT_DEMIBOLD, QFont::Medium, QFont::DemiBold);
57
0
    if (fcweight <= FC_WEIGHT_BOLD)
58
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_DEMIBOLD, FC_WEIGHT_BOLD, QFont::DemiBold, QFont::Bold);
59
0
    if (fcweight <= FC_WEIGHT_ULTRABOLD)
60
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_BOLD, FC_WEIGHT_ULTRABOLD, QFont::Bold, QFont::ExtraBold);
61
0
    if (fcweight <= FC_WEIGHT_BLACK)
62
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_ULTRABOLD, FC_WEIGHT_BLACK, QFont::ExtraBold, QFont::Black);
63
0
    if (fcweight <= FC_WEIGHT_ULTRABLACK)
64
0
        return mapToQtWeightForRange(fcweight, FC_WEIGHT_BLACK, FC_WEIGHT_ULTRABLACK, QFont::Black,
65
0
                                     QFONT_WEIGHT_MAX);
66
0
    return QFONT_WEIGHT_MAX;
67
0
}
68
69
static inline int stretchFromFcWidth(int fcwidth)
70
0
{
71
    // Font Config enums for width match pretty closely with those used by Qt so just use
72
    // Font Config values directly while enforcing the same limits imposed by QFont.
73
0
    const int maxStretch = 4000;
74
0
    int qtstretch;
75
0
    if (fcwidth < 1)
76
0
        qtstretch = 1;
77
0
    else if (fcwidth > maxStretch)
78
0
        qtstretch = maxStretch;
79
0
    else
80
0
        qtstretch = fcwidth;
81
82
0
    return qtstretch;
83
0
}
84
85
static const char specialLanguages[][6] = {
86
    "", // Unknown
87
    "", // Inherited
88
    "", // Common
89
    "en", // Latin
90
    "el", // Greek
91
    "ru", // Cyrillic
92
    "hy", // Armenian
93
    "he", // Hebrew
94
    "ar", // Arabic
95
    "syr", // Syriac
96
    "dv", // Thaana
97
    "hi", // Devanagari
98
    "bn", // Bengali
99
    "pa", // Gurmukhi
100
    "gu", // Gujarati
101
    "or", // Oriya
102
    "ta", // Tamil
103
    "te", // Telugu
104
    "kn", // Kannada
105
    "ml", // Malayalam
106
    "si", // Sinhala
107
    "th", // Thai
108
    "lo", // Lao
109
    "bo", // Tibetan
110
    "my", // Myanmar
111
    "ka", // Georgian
112
    "ko", // Hangul
113
    "am", // Ethiopic
114
    "chr", // Cherokee
115
    "cr", // CanadianAboriginal
116
    "sga", // Ogham
117
    "non", // Runic
118
    "km", // Khmer
119
    "mn", // Mongolian
120
    "ja", // Hiragana
121
    "ja", // Katakana
122
    "zh-TW", // Bopomofo
123
    "", // Han
124
    "ii", // Yi
125
    "ett", // OldItalic
126
    "got", // Gothic
127
    "en", // Deseret
128
    "fil", // Tagalog
129
    "hnn", // Hanunoo
130
    "bku", // Buhid
131
    "tbw", // Tagbanwa
132
    "cop", // Coptic
133
    "lif", // Limbu
134
    "tdd", // TaiLe
135
    "grc", // LinearB
136
    "uga", // Ugaritic
137
    "en", // Shavian
138
    "so", // Osmanya
139
    "grc", // Cypriot
140
    "", // Braille
141
    "bug", // Buginese
142
    "khb", // NewTaiLue
143
    "cu", // Glagolitic
144
    "shi", // Tifinagh
145
    "syl", // SylotiNagri
146
    "peo", // OldPersian
147
    "pra", // Kharoshthi
148
    "ban", // Balinese
149
    "akk", // Cuneiform
150
    "phn", // Phoenician
151
    "lzh", // PhagsPa
152
    "man", // Nko
153
    "su", // Sundanese
154
    "lep", // Lepcha
155
    "sat", // OlChiki
156
    "vai", // Vai
157
    "saz", // Saurashtra
158
    "eky", // KayahLi
159
    "rej", // Rejang
160
    "xlc", // Lycian
161
    "xcr", // Carian
162
    "xld", // Lydian
163
    "cjm", // Cham
164
    "nod", // TaiTham
165
    "blt", // TaiViet
166
    "ae", // Avestan
167
    "egy", // EgyptianHieroglyphs
168
    "smp", // Samaritan
169
    "lis", // Lisu
170
    "bax", // Bamum
171
    "jv", // Javanese
172
    "mni", // MeeteiMayek
173
    "arc", // ImperialAramaic
174
    "xsa", // OldSouthArabian
175
    "xpr", // InscriptionalParthian
176
    "pal", // InscriptionalPahlavi
177
    "otk", // OldTurkic
178
    "bh", // Kaithi
179
    "bbc", // Batak
180
    "pra", // Brahmi
181
    "myz", // Mandaic
182
    "ccp", // Chakma
183
    "xmr", // MeroiticCursive
184
    "xmr", // MeroiticHieroglyphs
185
    "hmd", // Miao
186
    "sa", // Sharada
187
    "srb", // SoraSompeng
188
    "doi", // Takri
189
    "lez", // CaucasianAlbanian
190
    "bsq", // BassaVah
191
    "fr", // Duployan
192
    "sq", // Elbasan
193
    "sa", // Grantha
194
    "hnj", // PahawhHmong
195
    "sd", // Khojki
196
    "lab", // LinearA
197
    "hi", // Mahajani
198
    "xmn", // Manichaean
199
    "men", // MendeKikakui
200
    "mr", // Modi
201
    "mru", // Mro
202
    "xna", // OldNorthArabian
203
    "arc", // Nabataean
204
    "arc", // Palmyrene
205
    "ctd", // PauCinHau
206
    "kv", // OldPermic
207
    "pal", // PsalterPahlavi
208
    "sa", // Siddham
209
    "sd", // Khudawadi
210
    "mai", // Tirhuta
211
    "hoc", // WarangCiti
212
    "", // Ahom
213
    "", // AnatolianHieroglyphs
214
    "", // Hatran
215
    "", // Multani
216
    "", // OldHungarian
217
    "", // SignWriting
218
    "", // Adlam
219
    "", // Bhaiksuki
220
    "", // Marchen
221
    "", // Newa
222
    "", // Osage
223
    "", // Tangut
224
    "", // MasaramGondi
225
    "", // Nushu
226
    "", // Soyombo
227
    "", // ZanabazarSquare
228
    "", // Dogra
229
    "", // GunjalaGondi
230
    "", // HanifiRohingya
231
    "", // Makasar
232
    "", // Medefaidrin
233
    "", // OldSogdian
234
    "", // Sogdian
235
    "", // Elymaic
236
    "", // Nandinagari
237
    "", // NyiakengPuachueHmong
238
    "", // Wancho
239
    "", // Chorasmian
240
    "", // DivesAkuru
241
    "", // KhitanSmallScript
242
    "", // Yezidi
243
    "", // CyproMinoan
244
    "", // OldUyghur
245
    "", // Tangsa
246
    "", // Toto
247
    "", // Vithkuqi
248
    "", // Kawi
249
    "", // NagMundari
250
    "", // Garay
251
    "", // GurungKhema
252
    "", // KiratRai
253
    "", // OlOnal
254
    "", // Sunuwar
255
    "", // Todhri
256
    "", // TuluTigalari
257
    "", // Sidetic
258
    "", // TaiYo
259
    "", // TolongSiki
260
    "", // BeriaErfe
261
};
262
static_assert(sizeof specialLanguages / sizeof *specialLanguages == QChar::ScriptCount);
263
264
// this could become a list of all languages used for each writing
265
// system, instead of using the single most common language.
266
static const char languageForWritingSystem[][6] = {
267
    "",     // Any
268
    "en",  // Latin
269
    "el",  // Greek
270
    "ru",  // Cyrillic
271
    "hy",  // Armenian
272
    "he",  // Hebrew
273
    "ar",  // Arabic
274
    "syr", // Syriac
275
    "div", // Thaana
276
    "hi",  // Devanagari
277
    "bn",  // Bengali
278
    "pa",  // Gurmukhi
279
    "gu",  // Gujarati
280
    "or",  // Oriya
281
    "ta",  // Tamil
282
    "te",  // Telugu
283
    "kn",  // Kannada
284
    "ml",  // Malayalam
285
    "si",  // Sinhala
286
    "th",  // Thai
287
    "lo",  // Lao
288
    "bo",  // Tibetan
289
    "my",  // Myanmar
290
    "ka",  // Georgian
291
    "km",  // Khmer
292
    "zh-cn", // SimplifiedChinese
293
    "zh-tw", // TraditionalChinese
294
    "ja",  // Japanese
295
    "ko",  // Korean
296
    "vi",  // Vietnamese
297
    "", // Symbol
298
    "sga", // Ogham
299
    "non", // Runic
300
    "man" // N'Ko
301
};
302
static_assert(sizeof languageForWritingSystem / sizeof *languageForWritingSystem == QFontDatabase::WritingSystemsCount);
303
304
#if FC_VERSION >= 20297
305
// Newer FontConfig let's us sort out fonts that report certain scripts support,
306
// but no open type tables for handling them correctly.
307
// Check the reported script presence in the FC_CAPABILITY's "otlayout:" section.
308
static const char capabilityForWritingSystem[][5] = {
309
    "",     // Any
310
    "",  // Latin
311
    "",  // Greek
312
    "",  // Cyrillic
313
    "",  // Armenian
314
    "",  // Hebrew
315
    "",  // Arabic
316
    "syrc",  // Syriac
317
    "thaa",  // Thaana
318
    "deva",  // Devanagari
319
    "beng",  // Bengali
320
    "guru",  // Gurmukhi
321
    "gujr",  // Gujarati
322
    "orya",  // Oriya
323
    "taml",  // Tamil
324
    "telu",  // Telugu
325
    "knda",  // Kannada
326
    "mlym",  // Malayalam
327
    "sinh",  // Sinhala
328
    "",  // Thai
329
    "",  // Lao
330
    "tibt",  // Tibetan
331
    "mymr",  // Myanmar
332
    "",  // Georgian
333
    "khmr",  // Khmer
334
    "", // SimplifiedChinese
335
    "", // TraditionalChinese
336
    "",  // Japanese
337
    "",  // Korean
338
    "",  // Vietnamese
339
    "", // Symbol
340
    "", // Ogham
341
    "", // Runic
342
    "nko " // N'Ko
343
};
344
static_assert(sizeof(capabilityForWritingSystem) / sizeof(*capabilityForWritingSystem) == QFontDatabase::WritingSystemsCount);
345
#endif
346
347
static const char *getFcFamilyForStyleHint(const QFont::StyleHint style)
348
0
{
349
0
    const char *stylehint = nullptr;
350
0
    switch (style) {
351
0
    case QFont::SansSerif:
352
0
        stylehint = "sans-serif";
353
0
        break;
354
0
    case QFont::Serif:
355
0
        stylehint = "serif";
356
0
        break;
357
0
    case QFont::TypeWriter:
358
0
    case QFont::Monospace:
359
0
        stylehint = "monospace";
360
0
        break;
361
0
    case QFont::Cursive:
362
0
        stylehint = "cursive";
363
0
        break;
364
0
    case QFont::Fantasy:
365
0
        stylehint = "fantasy";
366
0
        break;
367
0
    default:
368
0
        break;
369
0
    }
370
0
    return stylehint;
371
0
}
372
373
static inline bool requiresOpenType(int writingSystem)
374
0
{
375
0
    return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
376
0
            || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
377
0
}
378
379
static void populateFromPattern(FcPattern *pattern,
380
                                QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr,
381
                                FT_Face face = nullptr,
382
                                QFontconfigDatabase *db = nullptr)
383
0
{
384
0
    QString familyName;
385
0
    QString familyNameLang;
386
0
    FcChar8 *value = nullptr;
387
0
    int weight_value;
388
0
    int slant_value;
389
0
    int spacing_value;
390
0
    int width_value;
391
0
    FcChar8 *file_value;
392
0
    int indexValue;
393
0
    FcChar8 *foundry_value;
394
0
    FcChar8 *style_value;
395
0
    FcBool scalable;
396
0
    FcBool antialias;
397
398
0
    if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch)
399
0
        return;
400
401
0
    familyName = QString::fromUtf8((const char *)value);
402
403
0
    if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch)
404
0
        familyNameLang = QString::fromUtf8((const char *)value);
405
406
0
    slant_value = FC_SLANT_ROMAN;
407
0
    weight_value = FC_WEIGHT_REGULAR;
408
0
    spacing_value = FC_PROPORTIONAL;
409
0
    file_value = nullptr;
410
0
    indexValue = 0;
411
0
    scalable = FcTrue;
412
413
414
0
    if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch)
415
0
        slant_value = FC_SLANT_ROMAN;
416
0
    if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch)
417
0
        weight_value = FC_WEIGHT_REGULAR;
418
0
    if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch)
419
0
        width_value = FC_WIDTH_NORMAL;
420
0
    if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch)
421
0
        spacing_value = FC_PROPORTIONAL;
422
0
    if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch)
423
0
        file_value = nullptr;
424
0
    if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch)
425
0
        indexValue = 0;
426
0
    if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
427
0
        scalable = FcTrue;
428
0
    if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
429
0
        foundry_value = nullptr;
430
0
    if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch)
431
0
        style_value = nullptr;
432
0
    if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch)
433
0
        antialias = true;
434
435
0
    QSupportedWritingSystems writingSystems;
436
0
    FcLangSet *langset = nullptr;
437
0
    FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset);
438
0
    if (res == FcResultMatch) {
439
0
        bool hasLang = false;
440
0
#if FC_VERSION >= 20297
441
0
        FcChar8 *cap = nullptr;
442
0
        FcResult capRes = FcResultNoMatch;
443
0
#endif
444
0
        for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
445
0
            const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j];
446
0
            if (lang) {
447
0
                FcLangResult langRes = FcLangSetHasLang(langset, lang);
448
0
                if (langRes != FcLangDifferentLang) {
449
0
#if FC_VERSION >= 20297
450
0
                    if (*capabilityForWritingSystem[j] && requiresOpenType(j)) {
451
0
                        if (cap == nullptr)
452
0
                            capRes = FcPatternGetString(pattern, FC_CAPABILITY, 0, &cap);
453
0
                        if (capRes == FcResultMatch && strstr(reinterpret_cast<const char *>(cap), capabilityForWritingSystem[j]) == nullptr)
454
0
                            continue;
455
0
                    }
456
0
#endif
457
0
                    writingSystems.setSupported(QFontDatabase::WritingSystem(j));
458
0
                    hasLang = true;
459
0
                }
460
0
            }
461
0
        }
462
0
        if (!hasLang)
463
            // none of our known languages, add it to the other set
464
0
            writingSystems.setSupported(QFontDatabase::Other);
465
0
    } else {
466
        // we set Other to supported for symbol fonts. It makes no
467
        // sense to merge these with other ones, as they are
468
        // special in a way.
469
0
        writingSystems.setSupported(QFontDatabase::Other);
470
0
    }
471
472
0
    QString fileName = QString::fromLocal8Bit((const char *)file_value);
473
474
0
    QFont::Style style = (slant_value == FC_SLANT_ITALIC)
475
0
                     ? QFont::StyleItalic
476
0
                     : ((slant_value == FC_SLANT_OBLIQUE)
477
0
                        ? QFont::StyleOblique
478
0
                        : QFont::StyleNormal);
479
    // Note: weight should really be an int but registerFont incorrectly uses an enum
480
0
    QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value));
481
482
0
    double pixel_size = 0;
483
0
    if (!scalable)
484
0
        FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &pixel_size);
485
486
0
    bool fixedPitch = spacing_value >= FC_MONO;
487
488
0
    FcBool colorFont = false;
489
0
#ifdef FC_COLOR
490
0
    FcPatternGetBool(pattern, FC_COLOR, 0, &colorFont);
491
0
#endif
492
493
    // Note: stretch should really be an int but registerFont incorrectly uses an enum
494
0
    QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value));
495
0
    QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString();
496
497
0
    if (applicationFont != nullptr) {
498
0
        QFontDatabasePrivate::ApplicationFont::Properties properties;
499
0
        properties.familyName = familyName;
500
0
        properties.styleName = styleName;
501
0
        properties.weight = weight;
502
0
        properties.style = style;
503
0
        properties.stretch = stretch;
504
505
0
        applicationFont->properties.append(properties);
506
0
    }
507
508
0
    {
509
0
        FontFile *fontFile = new FontFile;
510
0
        fontFile->fileName = fileName;
511
0
        fontFile->indexValue = indexValue;
512
0
        QPlatformFontDatabase::registerFont(familyName,
513
0
                                            styleName,
514
0
                                            QLatin1StringView((const char *)foundry_value),
515
0
                                            weight,
516
0
                                            style,
517
0
                                            stretch,
518
0
                                            antialias,
519
0
                                            scalable,
520
0
                                            pixel_size,
521
0
                                            fixedPitch,
522
0
                                            colorFont,
523
0
                                            writingSystems,
524
0
                                            fontFile);
525
0
    }
526
0
    if (applicationFont != nullptr && face != nullptr && db != nullptr) {
527
0
        db->addNamedInstancesForFace(face,
528
0
                                     indexValue,
529
0
                                     familyName,
530
0
                                     styleName,
531
0
                                     weight,
532
0
                                     stretch,
533
0
                                     style,
534
0
                                     fixedPitch,
535
0
                                     colorFont,
536
0
                                     writingSystems,
537
0
                                     QByteArray((const char*)file_value),
538
0
                                     applicationFont->data);
539
0
    }
540
541
//        qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
542
543
0
    for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) {
544
0
        const QString altFamilyName = QString::fromUtf8((const char *)value);
545
        // Extra family names can be aliases or subfamilies.
546
        // If it is a subfamily, register it as a separate font, so only members of the subfamily are
547
        // matched when the subfamily is requested.
548
0
        QString altStyleName;
549
0
        if (FcPatternGetString(pattern, FC_STYLE, k, &value) == FcResultMatch)
550
0
            altStyleName = QString::fromUtf8((const char *)value);
551
0
        else
552
0
            altStyleName = styleName;
553
554
0
        QString altFamilyNameLang;
555
0
        if (FcPatternGetString(pattern, FC_FAMILYLANG, k, &value) == FcResultMatch)
556
0
            altFamilyNameLang = QString::fromUtf8((const char *)value);
557
0
        else
558
0
            altFamilyNameLang = familyNameLang;
559
560
0
        if (familyNameLang == altFamilyNameLang && altStyleName != styleName) {
561
0
            if (applicationFont != nullptr) {
562
0
                QFontDatabasePrivate::ApplicationFont::Properties properties;
563
0
                properties.familyName = altFamilyName;
564
0
                properties.styleName = altStyleName;
565
0
                properties.weight = weight;
566
0
                properties.style = style;
567
0
                properties.stretch = stretch;
568
569
0
                applicationFont->properties.append(properties);
570
0
            }
571
572
0
            {
573
0
                FontFile *altFontFile = new FontFile;
574
0
                altFontFile->fileName = fileName;
575
0
                altFontFile->indexValue = indexValue;
576
0
                QPlatformFontDatabase::registerFont(altFamilyName,
577
0
                                                    altStyleName,
578
0
                                                    QLatin1StringView((const char *)foundry_value),
579
0
                                                    weight,
580
0
                                                    style,
581
0
                                                    stretch,
582
0
                                                    antialias,
583
0
                                                    scalable,
584
0
                                                    pixel_size,
585
0
                                                    fixedPitch,
586
0
                                                    colorFont,
587
0
                                                    writingSystems,
588
0
                                                    altFontFile);
589
0
            }
590
0
        } else {
591
0
            QPlatformFontDatabase::registerAliasToFontFamily(familyName, altFamilyName);
592
0
        }
593
0
    }
594
595
0
}
596
597
static bool isDprScaling()
598
0
{
599
0
    return !qFuzzyCompare(qApp->devicePixelRatio(), qreal(1.0));
600
0
}
601
602
QFontconfigDatabase::~QFontconfigDatabase()
603
0
{
604
0
    FcConfigDestroy(FcConfigGetCurrent());
605
0
}
606
607
void QFontconfigDatabase::populateFontDatabase()
608
0
{
609
0
    FcInit();
610
0
    FcFontSet  *fonts;
611
612
0
    {
613
0
        FcObjectSet *os = FcObjectSetCreate();
614
0
        FcPattern *pattern = FcPatternCreate();
615
0
        const char *properties [] = {
616
0
            FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT,
617
0
            FC_SPACING, FC_FILE, FC_INDEX,
618
0
            FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE,
619
0
            FC_WIDTH, FC_FAMILYLANG,
620
0
#if FC_VERSION >= 20297
621
0
            FC_CAPABILITY,
622
0
#endif
623
0
#if defined(FC_COLOR)
624
0
            FC_COLOR,
625
0
#endif
626
0
            (const char *)nullptr
627
0
        };
628
0
        const char **p = properties;
629
0
        while (*p) {
630
0
            FcObjectSetAdd(os, *p);
631
0
            ++p;
632
0
        }
633
634
0
#ifdef FC_VARIABLE
635
        /* Support the named instance of Variable Fonts. */
636
0
        FcPatternAddBool(pattern, FC_VARIABLE, FcFalse);
637
0
#endif
638
639
0
        fonts = FcFontList(nullptr, pattern, os);
640
0
        FcObjectSetDestroy(os);
641
0
        FcPatternDestroy(pattern);
642
0
        if (!fonts)
643
0
            return;
644
0
    }
645
646
0
    for (int i = 0; i < fonts->nfont; i++)
647
0
        populateFromPattern(fonts->fonts[i]);
648
649
0
    FcFontSetDestroy (fonts);
650
651
0
    struct FcDefaultFont {
652
0
        const char *qtname;
653
0
        const char *rawname;
654
0
        bool fixed;
655
0
    };
656
0
    const FcDefaultFont defaults[] = {
657
0
        { "Serif", "serif", false },
658
0
        { "Sans Serif", "sans-serif", false },
659
0
        { "Monospace", "monospace", true },
660
0
        { nullptr, nullptr, false }
661
0
    };
662
0
    const FcDefaultFont *f = defaults;
663
    // aliases only make sense for 'common', not for any of the specials
664
0
    QSupportedWritingSystems ws;
665
0
    ws.setSupported(QFontDatabase::Latin);
666
667
0
    while (f->qtname) {
668
0
        QString familyQtName = QString::fromLatin1(f->qtname);
669
0
        registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,false,ws,nullptr);
670
0
        registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,false,ws,nullptr);
671
0
        registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,false,ws,nullptr);
672
0
        ++f;
673
0
    }
674
675
    //QPA has very lazy population of the font db. We want it to be initialized when
676
    //QApplication is constructed, so that the population procedure can do something like this to
677
    //set the default font
678
//    const FcDefaultFont *s = defaults;
679
//    QFont font("Sans Serif");
680
//    font.setPointSize(9);
681
//    QApplication::setFont(font);
682
0
}
683
684
void QFontconfigDatabase::invalidate()
685
0
{
686
    // Clear app fonts.
687
0
    FcConfigAppFontClear(nullptr);
688
0
}
689
690
QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine, QFontDatabasePrivate::ExtendedScript script)
691
0
{
692
0
    return new QFontEngineMultiFontConfig(fontEngine, script);
693
0
}
694
695
namespace {
696
QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool preferXftConf)
697
0
{
698
0
    switch (hintingPreference) {
699
0
    case QFont::PreferNoHinting:
700
0
        return QFontEngine::HintNone;
701
0
    case QFont::PreferVerticalHinting:
702
0
        return QFontEngine::HintLight;
703
0
    case QFont::PreferFullHinting:
704
0
        return QFontEngine::HintFull;
705
0
    case QFont::PreferDefaultHinting:
706
0
        break;
707
0
    }
708
709
0
    if (isDprScaling())
710
0
        return QFontEngine::HintNone;
711
712
0
    void *hintStyleResource =
713
0
            QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
714
0
                                                                                QGuiApplication::primaryScreen());
715
0
    int xftHintStyle =  int(reinterpret_cast<qintptr>(hintStyleResource));
716
0
    if (preferXftConf && xftHintStyle > 0)
717
0
        return QFontEngine::HintStyle(xftHintStyle - 1);
718
719
0
    int hint_style = 0;
720
0
    if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultMatch) {
721
0
        switch (hint_style) {
722
0
        case FC_HINT_NONE:
723
0
            return QFontEngine::HintNone;
724
0
        case FC_HINT_SLIGHT:
725
0
            return QFontEngine::HintLight;
726
0
        case FC_HINT_MEDIUM:
727
0
            return QFontEngine::HintMedium;
728
0
        case FC_HINT_FULL:
729
0
            return QFontEngine::HintFull;
730
0
        default:
731
0
            Q_UNREACHABLE();
732
0
            break;
733
0
        }
734
0
    }
735
0
    if (xftHintStyle > 0)
736
0
        return QFontEngine::HintStyle(xftHintStyle - 1);
737
738
0
    return QFontEngine::HintFull;
739
0
}
740
741
QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool preferXftConf)
742
0
{
743
0
    void *subpixelTypeResource =
744
0
            QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
745
0
                                                                                QGuiApplication::primaryScreen());
746
0
    int xftSubpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
747
0
    if (preferXftConf && xftSubpixelType > 0)
748
0
        return QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
749
750
0
    int subpixel = FC_RGBA_UNKNOWN;
751
0
    if (FcPatternGetInteger(match, FC_RGBA, 0, &subpixel) == FcResultMatch) {
752
0
        switch (subpixel) {
753
0
        case FC_RGBA_UNKNOWN:
754
0
        case FC_RGBA_NONE:
755
0
            return QFontEngine::Subpixel_None;
756
0
        case FC_RGBA_RGB:
757
0
            return QFontEngine::Subpixel_RGB;
758
0
        case FC_RGBA_BGR:
759
0
            return QFontEngine::Subpixel_BGR;
760
0
        case FC_RGBA_VRGB:
761
0
            return QFontEngine::Subpixel_VRGB;
762
0
        case FC_RGBA_VBGR:
763
0
            return QFontEngine::Subpixel_VBGR;
764
0
        default:
765
0
            Q_UNREACHABLE();
766
0
            break;
767
0
        }
768
0
    }
769
770
0
    if (xftSubpixelType > 0)
771
0
        return QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
772
773
0
    return QFontEngine::Subpixel_None;
774
0
}
775
} // namespace
776
777
QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
778
0
{
779
0
    if (!usrPtr)
780
0
        return nullptr;
781
782
0
    FontFile *fontfile = static_cast<FontFile *> (usrPtr);
783
0
    QFontEngine::FaceId fid;
784
0
    fid.filename = QFile::encodeName(fontfile->fileName);
785
0
    fid.index = fontfile->indexValue;
786
0
    fid.instanceIndex = fontfile->instanceIndex;
787
0
    fid.variableAxes = f.variableAxisValues;
788
789
    // FIXME: Unify with logic in QFontEngineFT::create()
790
0
    QFontEngineFT *engine = new QFontEngineFT(f);
791
0
    engine->face_id = fid;
792
793
0
    setupFontEngine(engine, f);
794
795
0
    if (!engine->init(fid, engine->antialias, engine->defaultFormat) || engine->invalid()) {
796
0
        delete engine;
797
0
        engine = nullptr;
798
0
    }
799
800
0
    return engine;
801
0
}
802
803
QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
804
0
{
805
0
    QFontEngineFT *engine = static_cast<QFontEngineFT*>(QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference));
806
0
    if (engine == nullptr)
807
0
        return nullptr;
808
809
0
    setupFontEngine(engine, engine->fontDef);
810
811
0
    return engine;
812
0
}
813
814
QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family,
815
                                                    QFont::Style style,
816
                                                    QFont::StyleHint styleHint,
817
                                                    QFontDatabasePrivate::ExtendedScript script) const
818
0
{
819
0
    QStringList fallbackFamilies;
820
0
    FcPattern *pattern = FcPatternCreate();
821
0
    if (!pattern)
822
0
        return fallbackFamilies;
823
824
0
    FcValue value;
825
0
    value.type = FcTypeString;
826
0
    const QByteArray cs = family.toUtf8();
827
0
    value.u.s = (const FcChar8 *)cs.data();
828
0
    FcPatternAdd(pattern,FC_FAMILY,value,true);
829
830
0
#ifdef FC_COLOR
831
0
    if (script == QFontDatabasePrivate::Script_Emoji) {
832
0
        FcPatternAddBool(pattern, FC_COLOR, true);
833
0
        value.u.s = (const FcChar8 *)"emoji";
834
0
        FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
835
0
    }
836
0
#endif
837
838
0
    int slant_value = FC_SLANT_ROMAN;
839
0
    if (style == QFont::StyleItalic)
840
0
        slant_value = FC_SLANT_ITALIC;
841
0
    else if (style == QFont::StyleOblique)
842
0
        slant_value = FC_SLANT_OBLIQUE;
843
0
    FcPatternAddInteger(pattern, FC_SLANT, slant_value);
844
845
0
    Q_ASSERT(uint(script) < QFontDatabasePrivate::ScriptCount);
846
0
    if (uint(script) < QChar::ScriptCount && *specialLanguages[script] != '\0') {
847
0
        FcLangSet *ls = FcLangSetCreate();
848
0
        FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
849
0
        FcPatternAddLangSet(pattern, FC_LANG, ls);
850
0
        FcLangSetDestroy(ls);
851
0
    } else if (!family.isEmpty()) {
852
        // If script is Common or Han, then it may include languages like CJK,
853
        // we should attach system default language set to the pattern
854
        // to obtain correct font fallback list (i.e. if LANG=zh_CN
855
        // then we normally want to use a Chinese font for CJK text;
856
        // while a Japanese font should be used for that if LANG=ja)
857
0
        FcPattern *dummy = FcPatternCreate();
858
0
        FcDefaultSubstitute(dummy);
859
0
        FcChar8 *lang = nullptr;
860
0
        FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang);
861
0
        if (res == FcResultMatch)
862
0
            FcPatternAddString(pattern, FC_LANG, lang);
863
0
        FcPatternDestroy(dummy);
864
0
    }
865
866
0
    const char *stylehint = getFcFamilyForStyleHint(styleHint);
867
0
    if (stylehint) {
868
0
        value.u.s = (const FcChar8 *)stylehint;
869
0
        FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
870
0
    }
871
872
0
    FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
873
0
    FcDefaultSubstitute(pattern);
874
875
0
    FcResult result = FcResultMatch;
876
0
    FcFontSet *fontSet = FcFontSort(nullptr,pattern,FcFalse,nullptr,&result);
877
0
    FcPatternDestroy(pattern);
878
879
0
    if (fontSet) {
880
0
        QDuplicateTracker<QString> duplicates(fontSet->nfont + 1);
881
0
        (void)duplicates.hasSeen(family.toCaseFolded());
882
0
        for (int i = 0; i < fontSet->nfont; i++) {
883
0
            FcChar8 *value = nullptr;
884
0
            if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
885
0
                continue;
886
            //         capitalize(value);
887
0
            const QString familyName = QString::fromUtf8((const char *)value);
888
0
            const QString familyNameCF = familyName.toCaseFolded();
889
0
            if (!duplicates.hasSeen(familyNameCF)) {
890
0
                fallbackFamilies << familyName;
891
0
            }
892
0
        }
893
0
        FcFontSetDestroy(fontSet);
894
0
    }
895
//    qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies;
896
897
0
    return fallbackFamilies;
898
0
}
899
900
static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count, FT_Face *face)
901
0
{
902
#if FC_VERSION < 20402
903
    Q_UNUSED(data);
904
    *face = nullptr;
905
    return FcFreeTypeQuery(file, id, blanks, count);
906
#else
907
0
    if (data.isEmpty()) {
908
0
        *face = nullptr;
909
0
        return FcFreeTypeQuery(file, id, blanks, count);
910
0
    }
911
912
0
    FT_Library lib = qt_getFreetype();
913
914
0
    FcPattern *pattern = nullptr;
915
916
0
    if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, face)) {
917
0
        *count = (*face)->num_faces;
918
919
0
        pattern = FcFreeTypeQueryFace(*face, file, id, blanks);
920
0
    } else {
921
0
        *face = nullptr;
922
0
    }
923
924
0
    return pattern;
925
0
#endif
926
0
}
927
928
QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
929
0
{
930
0
    QStringList families;
931
932
0
    if (applicationFont != nullptr)
933
0
        applicationFont->properties.clear();
934
935
0
    FcFontSet *set = FcConfigGetFonts(nullptr, FcSetApplication);
936
0
    if (!set) {
937
0
        FcConfigAppFontAddFile(nullptr, (const FcChar8 *)":/non-existent");
938
0
        set = FcConfigGetFonts(nullptr, FcSetApplication); // try again
939
0
        if (!set)
940
0
            return families;
941
0
    }
942
943
0
    int id = 0;
944
0
    FcBlanks *blanks = FcConfigGetBlanks(nullptr);
945
0
    int count = 0;
946
947
0
    FcPattern *pattern;
948
0
    do {
949
0
        FT_Face face;
950
0
        pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
951
0
                            fontData, id, blanks, &count, &face);
952
0
        if (!pattern)
953
0
            return families;
954
955
0
        FcChar8 *fam = nullptr;
956
0
        if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
957
0
            QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
958
0
            families << family;
959
0
        }
960
0
        populateFromPattern(pattern, applicationFont, face, this);
961
962
0
        if (face)
963
0
            FT_Done_Face(face);
964
965
0
        FcFontSetAdd(set, pattern);
966
967
0
        ++id;
968
0
    } while (id < count);
969
970
0
    return families;
971
0
}
972
973
QString QFontconfigDatabase::resolveFontFamilyAlias(const QString &family) const
974
0
{
975
0
    QString resolved = QFreeTypeFontDatabase::resolveFontFamilyAlias(family);
976
0
    if (!resolved.isEmpty() && resolved != family)
977
0
        return resolved;
978
0
    FcPattern *pattern = FcPatternCreate();
979
0
    if (!pattern)
980
0
        return family;
981
982
0
    if (!family.isEmpty()) {
983
0
        const QByteArray cs = family.toUtf8();
984
0
        FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData());
985
0
    }
986
0
    FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
987
0
    FcDefaultSubstitute(pattern);
988
989
0
    FcChar8 *familyAfterSubstitution = nullptr;
990
0
    FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
991
0
    resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
992
0
    FcPatternDestroy(pattern);
993
994
0
    return resolved;
995
0
}
996
997
QFont QFontconfigDatabase::defaultFont() const
998
0
{
999
    // Hack to get system default language until FcGetDefaultLangs()
1000
    // is exported (https://bugs.freedesktop.org/show_bug.cgi?id=32853)
1001
    // or https://bugs.freedesktop.org/show_bug.cgi?id=35482 is fixed
1002
0
    FcPattern *dummy = FcPatternCreate();
1003
0
    FcDefaultSubstitute(dummy);
1004
0
    FcChar8 *lang = nullptr;
1005
0
    FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang);
1006
1007
0
    FcPattern *pattern = FcPatternCreate();
1008
0
    if (res == FcResultMatch) {
1009
        // Make defaultFont pattern matching locale language aware, because
1010
        // certain FC_LANG based custom rules may happen in FcConfigSubstitute()
1011
0
        FcPatternAddString(pattern, FC_LANG, lang);
1012
0
    }
1013
0
    FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
1014
0
    FcDefaultSubstitute(pattern);
1015
1016
0
    FcChar8 *familyAfterSubstitution = nullptr;
1017
0
    FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
1018
0
    QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
1019
0
    FcPatternDestroy(pattern);
1020
0
    FcPatternDestroy(dummy);
1021
1022
0
    return QFont(resolved);
1023
0
}
1024
1025
void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const
1026
0
{
1027
0
    bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
1028
0
    bool forcedAntialiasSetting = !antialias || isDprScaling();
1029
1030
0
    const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
1031
0
    bool preferXftConf = false;
1032
1033
0
    if (services) {
1034
0
        const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':');
1035
0
        preferXftConf = !(desktopEnv.contains("KDE") || desktopEnv.contains("LXQT") || desktopEnv.contains("UKUI"));
1036
0
    }
1037
1038
0
    QFontEngine::GlyphFormat format;
1039
    // try and get the pattern
1040
0
    FcPattern *pattern = FcPatternCreate();
1041
0
    FcPattern *match = nullptr;
1042
1043
0
    FcValue value;
1044
0
    value.type = FcTypeString;
1045
0
    QByteArray cs = fontDef.families.first().toUtf8();
1046
0
    value.u.s = (const FcChar8 *)cs.data();
1047
0
    FcPatternAdd(pattern,FC_FAMILY,value,true);
1048
1049
0
    QFontEngine::FaceId fid = engine->faceId();
1050
1051
0
    if (!fid.filename.isEmpty()) {
1052
0
        value.u.s = (const FcChar8 *)fid.filename.data();
1053
0
        FcPatternAdd(pattern,FC_FILE,value,true);
1054
1055
0
        value.type = FcTypeInteger;
1056
0
        value.u.i = fid.index;
1057
0
        FcPatternAdd(pattern,FC_INDEX,value,true);
1058
0
    }
1059
1060
0
    if (!qFuzzyIsNull(fontDef.pixelSize))
1061
0
        FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDef.pixelSize);
1062
1063
0
    FcResult result;
1064
1065
0
    FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
1066
0
    FcDefaultSubstitute(pattern);
1067
1068
0
#ifdef FC_VARIABLE
1069
0
    if (!fid.filename.isEmpty()) {
1070
        // FC_INDEX is ignored during processing in FcFontMatch.
1071
        // So iterate FcPatterns directly and find it out.
1072
0
        FcFontSet *fcsets[2], *fcfs;
1073
1074
0
        fcsets[0] = FcConfigGetFonts(nullptr, FcSetSystem);
1075
0
        fcsets[1] = FcConfigGetFonts(nullptr, FcSetApplication);
1076
0
        for (int nset = 0; nset < 2; nset++) {
1077
0
            fcfs = fcsets[nset];
1078
0
            if (fcfs == nullptr)
1079
0
                continue;
1080
0
            for (int fnum = 0; fnum < fcfs->nfont; fnum++) {
1081
0
                FcPattern *fcpat = fcfs->fonts[fnum];
1082
0
                FcChar8 *fcfile;
1083
0
                FcBool variable;
1084
0
                double fcpixelsize;
1085
0
                int fcindex;
1086
1087
                // Skip the variable font itself, only to use the named instances and normal fonts here
1088
0
                if (FcPatternGetBool(fcpat, FC_VARIABLE, 0, &variable) == FcResultMatch &&
1089
0
                    variable == FcTrue)
1090
0
                    continue;
1091
1092
0
                if (!qFuzzyIsNull(fontDef.pixelSize)) {
1093
0
                    if (FcPatternGetDouble(fcpat, FC_PIXEL_SIZE, 0, &fcpixelsize) == FcResultMatch &&
1094
0
                        fontDef.pixelSize != fcpixelsize)
1095
0
                    continue;
1096
0
                }
1097
1098
0
                if (FcPatternGetString(fcpat, FC_FILE, 0, &fcfile) == FcResultMatch &&
1099
0
                    FcPatternGetInteger(fcpat, FC_INDEX, 0, &fcindex) == FcResultMatch) {
1100
0
                    QByteArray f = QByteArray::fromRawData((const char *)fcfile,
1101
0
                                                           qstrlen((const char *)fcfile));
1102
0
                    if (f == fid.filename && fcindex == fid.index) {
1103
                        // We found it.
1104
0
                        match = FcFontRenderPrepare(nullptr, pattern, fcpat);
1105
0
                        goto bail;
1106
0
                    }
1107
0
                }
1108
0
            }
1109
0
        }
1110
0
    }
1111
0
bail:
1112
0
#endif
1113
1114
0
    if (!match)
1115
0
        match = FcFontMatch(nullptr, pattern, &result);
1116
1117
0
    int xftAntialias = 0;
1118
0
    if (!forcedAntialiasSetting) {
1119
0
        void *antialiasResource =
1120
0
                QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
1121
0
                                                                                    QGuiApplication::primaryScreen());
1122
0
        xftAntialias = int(reinterpret_cast<qintptr>(antialiasResource));
1123
0
        if ((preferXftConf || !match) && xftAntialias > 0) {
1124
0
            antialias = xftAntialias - 1;
1125
0
            forcedAntialiasSetting = true;
1126
0
        }
1127
0
    }
1128
0
    if (match) {
1129
0
        engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, preferXftConf));
1130
1131
0
        FcBool fc_autohint;
1132
0
        if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
1133
0
            engine->forceAutoHint = fc_autohint;
1134
1135
0
#if defined(FT_LCD_FILTER_H)
1136
0
        int lcdFilter;
1137
0
        if (FcPatternGetInteger(match, FC_LCD_FILTER, 0, &lcdFilter) == FcResultMatch)
1138
0
            engine->lcdFilterType = lcdFilter;
1139
0
#endif
1140
1141
0
        if (!forcedAntialiasSetting) {
1142
0
            FcBool fc_antialias;
1143
0
            if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch)
1144
0
                antialias = fc_antialias;
1145
0
        }
1146
1147
0
        if (antialias) {
1148
0
            QFontEngine::SubpixelAntialiasingType subpixelType = QFontEngine::Subpixel_None;
1149
0
            if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias))
1150
0
                subpixelType = subpixelTypeFromMatch(match, preferXftConf);
1151
0
            engine->subpixelType = subpixelType;
1152
0
        }
1153
1154
0
        FcPatternDestroy(match);
1155
0
    } else {
1156
0
        void *hintStyleResource =
1157
0
                QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
1158
0
                                                                                    QGuiApplication::primaryScreen());
1159
0
        int xftHintStyle =  int(reinterpret_cast<qintptr>(hintStyleResource));
1160
0
        if (xftHintStyle > 0)
1161
0
            engine->setDefaultHintStyle(QFontEngine::HintStyle(xftHintStyle - 1));
1162
0
        if (antialias) {
1163
0
            engine->subpixelType = QFontEngine::Subpixel_None;
1164
0
            if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
1165
0
                void *subpixelTypeResource =
1166
0
                        QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
1167
0
                                                                                            QGuiApplication::primaryScreen());
1168
0
                int xftSubpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
1169
0
                if (xftSubpixelType > 1)
1170
0
                    engine->subpixelType = QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
1171
0
            }
1172
0
        }
1173
0
    }
1174
0
    if (antialias) {
1175
0
        format = (engine->subpixelType == QFontEngine::Subpixel_None)
1176
0
                ? QFontEngine::Format_A8
1177
0
                : QFontEngine::Format_A32;
1178
0
    } else {
1179
0
        format = QFontEngine::Format_Mono;
1180
0
    }
1181
1182
0
    FcPatternDestroy(pattern);
1183
1184
0
    engine->antialias = antialias;
1185
0
    engine->defaultFormat = format;
1186
0
    engine->glyphFormat = format;
1187
0
}
1188
1189
bool QFontconfigDatabase::supportsVariableApplicationFonts() const
1190
0
{
1191
0
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
1192
0
    return true;
1193
#else
1194
    return false;
1195
#endif
1196
0
}
1197
1198
QT_END_NAMESPACE