Coverage Report

Created: 2026-07-30 07:17

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