Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qfontconfigdatabase.cpp
Go to the documentation of this file.
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
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#include <QtGui/private/qhighdpiscaling_p.h>
20
21#include <QtGui/qguiapplication.h>
22
23#include <QtCore/private/qduplicatetracker_p.h>
24
25#include <fontconfig/fontconfig.h>
26#if FC_VERSION >= 20402
27#include <fontconfig/fcfreetype.h>
28#endif
29
31
32static inline int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, int qtLower, int qtUpper)
33{
34 return qtLower + ((fcweight - fcLower) * (qtUpper - qtLower)) / (fcUpper - fcLower);
35}
36
37static inline int weightFromFcWeight(int fcweight)
38{
39 // Font Config uses weights from 0 to 215 (the highest enum value) while QFont ranges from
40 // 1 to 1000. The spacing between the values for the enums are uneven so a linear mapping from
41 // Font Config values to Qt would give surprising results. So, we do a piecewise linear
42 // mapping. This ensures that where there is a corresponding enum on both sides (for example
43 // FC_WEIGHT_DEMIBOLD and QFont::DemiBold) we map one to the other but other values map
44 // to intermediate Qt weights.
45
46 if (fcweight <= FC_WEIGHT_THIN)
47 return QFont::Thin;
48 if (fcweight <= FC_WEIGHT_ULTRALIGHT)
49 return mapToQtWeightForRange(fcweight, FC_WEIGHT_THIN, FC_WEIGHT_ULTRALIGHT, QFont::Thin, QFont::ExtraLight);
50 if (fcweight <= FC_WEIGHT_LIGHT)
51 return mapToQtWeightForRange(fcweight, FC_WEIGHT_ULTRALIGHT, FC_WEIGHT_LIGHT, QFont::ExtraLight, QFont::Light);
52 if (fcweight <= FC_WEIGHT_NORMAL)
53 return mapToQtWeightForRange(fcweight, FC_WEIGHT_LIGHT, FC_WEIGHT_NORMAL, QFont::Light, QFont::Normal);
54 if (fcweight <= FC_WEIGHT_MEDIUM)
55 return mapToQtWeightForRange(fcweight, FC_WEIGHT_NORMAL, FC_WEIGHT_MEDIUM, QFont::Normal, QFont::Medium);
56 if (fcweight <= FC_WEIGHT_DEMIBOLD)
57 return mapToQtWeightForRange(fcweight, FC_WEIGHT_MEDIUM, FC_WEIGHT_DEMIBOLD, QFont::Medium, QFont::DemiBold);
58 if (fcweight <= FC_WEIGHT_BOLD)
59 return mapToQtWeightForRange(fcweight, FC_WEIGHT_DEMIBOLD, FC_WEIGHT_BOLD, QFont::DemiBold, QFont::Bold);
60 if (fcweight <= FC_WEIGHT_ULTRABOLD)
61 return mapToQtWeightForRange(fcweight, FC_WEIGHT_BOLD, FC_WEIGHT_ULTRABOLD, QFont::Bold, QFont::ExtraBold);
62 if (fcweight <= FC_WEIGHT_BLACK)
63 return mapToQtWeightForRange(fcweight, FC_WEIGHT_ULTRABOLD, FC_WEIGHT_BLACK, QFont::ExtraBold, QFont::Black);
64 if (fcweight <= FC_WEIGHT_ULTRABLACK)
65 return mapToQtWeightForRange(fcweight, FC_WEIGHT_BLACK, FC_WEIGHT_ULTRABLACK, QFont::Black,
67 return QFONT_WEIGHT_MAX;
68}
69
70static inline int stretchFromFcWidth(int fcwidth)
71{
72 // Font Config enums for width match pretty closely with those used by Qt so just use
73 // Font Config values directly while enforcing the same limits imposed by QFont.
74 const int maxStretch = 4000;
75 int qtstretch;
76 if (fcwidth < 1)
77 qtstretch = 1;
78 else if (fcwidth > maxStretch)
79 qtstretch = maxStretch;
80 else
81 qtstretch = fcwidth;
82
83 return qtstretch;
84}
85
86static const char specialLanguages[][6] = {
87 "", // Unknown
88 "", // Inherited
89 "", // Common
90 "en", // Latin
91 "el", // Greek
92 "ru", // Cyrillic
93 "hy", // Armenian
94 "he", // Hebrew
95 "ar", // Arabic
96 "syr", // Syriac
97 "dv", // Thaana
98 "hi", // Devanagari
99 "bn", // Bengali
100 "pa", // Gurmukhi
101 "gu", // Gujarati
102 "or", // Oriya
103 "ta", // Tamil
104 "te", // Telugu
105 "kn", // Kannada
106 "ml", // Malayalam
107 "si", // Sinhala
108 "th", // Thai
109 "lo", // Lao
110 "bo", // Tibetan
111 "my", // Myanmar
112 "ka", // Georgian
113 "ko", // Hangul
114 "am", // Ethiopic
115 "chr", // Cherokee
116 "cr", // CanadianAboriginal
117 "sga", // Ogham
118 "non", // Runic
119 "km", // Khmer
120 "mn", // Mongolian
121 "ja", // Hiragana
122 "ja", // Katakana
123 "zh-TW", // Bopomofo
124 "", // Han
125 "ii", // Yi
126 "ett", // OldItalic
127 "got", // Gothic
128 "en", // Deseret
129 "fil", // Tagalog
130 "hnn", // Hanunoo
131 "bku", // Buhid
132 "tbw", // Tagbanwa
133 "cop", // Coptic
134 "lif", // Limbu
135 "tdd", // TaiLe
136 "grc", // LinearB
137 "uga", // Ugaritic
138 "en", // Shavian
139 "so", // Osmanya
140 "grc", // Cypriot
141 "", // Braille
142 "bug", // Buginese
143 "khb", // NewTaiLue
144 "cu", // Glagolitic
145 "shi", // Tifinagh
146 "syl", // SylotiNagri
147 "peo", // OldPersian
148 "pra", // Kharoshthi
149 "ban", // Balinese
150 "akk", // Cuneiform
151 "phn", // Phoenician
152 "lzh", // PhagsPa
153 "man", // Nko
154 "su", // Sundanese
155 "lep", // Lepcha
156 "sat", // OlChiki
157 "vai", // Vai
158 "saz", // Saurashtra
159 "eky", // KayahLi
160 "rej", // Rejang
161 "xlc", // Lycian
162 "xcr", // Carian
163 "xld", // Lydian
164 "cjm", // Cham
165 "nod", // TaiTham
166 "blt", // TaiViet
167 "ae", // Avestan
168 "egy", // EgyptianHieroglyphs
169 "smp", // Samaritan
170 "lis", // Lisu
171 "bax", // Bamum
172 "jv", // Javanese
173 "mni", // MeeteiMayek
174 "arc", // ImperialAramaic
175 "xsa", // OldSouthArabian
176 "xpr", // InscriptionalParthian
177 "pal", // InscriptionalPahlavi
178 "otk", // OldTurkic
179 "bh", // Kaithi
180 "bbc", // Batak
181 "pra", // Brahmi
182 "myz", // Mandaic
183 "ccp", // Chakma
184 "xmr", // MeroiticCursive
185 "xmr", // MeroiticHieroglyphs
186 "hmd", // Miao
187 "sa", // Sharada
188 "srb", // SoraSompeng
189 "doi", // Takri
190 "lez", // CaucasianAlbanian
191 "bsq", // BassaVah
192 "fr", // Duployan
193 "sq", // Elbasan
194 "sa", // Grantha
195 "hnj", // PahawhHmong
196 "sd", // Khojki
197 "lab", // LinearA
198 "hi", // Mahajani
199 "xmn", // Manichaean
200 "men", // MendeKikakui
201 "mr", // Modi
202 "mru", // Mro
203 "xna", // OldNorthArabian
204 "arc", // Nabataean
205 "arc", // Palmyrene
206 "ctd", // PauCinHau
207 "kv", // OldPermic
208 "pal", // PsalterPahlavi
209 "sa", // Siddham
210 "sd", // Khudawadi
211 "mai", // Tirhuta
212 "hoc", // WarangCiti
213 "", // Ahom
214 "", // AnatolianHieroglyphs
215 "", // Hatran
216 "", // Multani
217 "", // OldHungarian
218 "", // SignWriting
219 "", // Adlam
220 "", // Bhaiksuki
221 "", // Marchen
222 "", // Newa
223 "", // Osage
224 "", // Tangut
225 "", // MasaramGondi
226 "", // Nushu
227 "", // Soyombo
228 "", // ZanabazarSquare
229 "", // Dogra
230 "", // GunjalaGondi
231 "", // HanifiRohingya
232 "", // Makasar
233 "", // Medefaidrin
234 "", // OldSogdian
235 "", // Sogdian
236 "", // Elymaic
237 "", // Nandinagari
238 "", // NyiakengPuachueHmong
239 "", // Wancho
240 "", // Chorasmian
241 "", // DivesAkuru
242 "", // KhitanSmallScript
243 "", // Yezidi
244 "", // CyproMinoan
245 "", // OldUyghur
246 "", // Tangsa
247 "", // Toto
248 "", // Vithkuqi
249 "", // Kawi
250 "", // NagMundari
251};
252static_assert(sizeof specialLanguages / sizeof *specialLanguages == QChar::ScriptCount);
253
254// this could become a list of all languages used for each writing
255// system, instead of using the single most common language.
256static const char languageForWritingSystem[][6] = {
257 "", // Any
258 "en", // Latin
259 "el", // Greek
260 "ru", // Cyrillic
261 "hy", // Armenian
262 "he", // Hebrew
263 "ar", // Arabic
264 "syr", // Syriac
265 "div", // Thaana
266 "hi", // Devanagari
267 "bn", // Bengali
268 "pa", // Gurmukhi
269 "gu", // Gujarati
270 "or", // Oriya
271 "ta", // Tamil
272 "te", // Telugu
273 "kn", // Kannada
274 "ml", // Malayalam
275 "si", // Sinhala
276 "th", // Thai
277 "lo", // Lao
278 "bo", // Tibetan
279 "my", // Myanmar
280 "ka", // Georgian
281 "km", // Khmer
282 "zh-cn", // SimplifiedChinese
283 "zh-tw", // TraditionalChinese
284 "ja", // Japanese
285 "ko", // Korean
286 "vi", // Vietnamese
287 "", // Symbol
288 "sga", // Ogham
289 "non", // Runic
290 "man" // N'Ko
291};
293
294#if FC_VERSION >= 20297
295// Newer FontConfig let's us sort out fonts that report certain scripts support,
296// but no open type tables for handling them correctly.
297// Check the reported script presence in the FC_CAPABILITY's "otlayout:" section.
298static const char capabilityForWritingSystem[][5] = {
299 "", // Any
300 "", // Latin
301 "", // Greek
302 "", // Cyrillic
303 "", // Armenian
304 "", // Hebrew
305 "", // Arabic
306 "syrc", // Syriac
307 "thaa", // Thaana
308 "deva", // Devanagari
309 "beng", // Bengali
310 "guru", // Gurmukhi
311 "gujr", // Gujarati
312 "orya", // Oriya
313 "taml", // Tamil
314 "telu", // Telugu
315 "knda", // Kannada
316 "mlym", // Malayalam
317 "sinh", // Sinhala
318 "", // Thai
319 "", // Lao
320 "tibt", // Tibetan
321 "mymr", // Myanmar
322 "", // Georgian
323 "khmr", // Khmer
324 "", // SimplifiedChinese
325 "", // TraditionalChinese
326 "", // Japanese
327 "", // Korean
328 "", // Vietnamese
329 "", // Symbol
330 "", // Ogham
331 "", // Runic
332 "nko " // N'Ko
333};
334static_assert(sizeof(capabilityForWritingSystem) / sizeof(*capabilityForWritingSystem) == QFontDatabase::WritingSystemsCount);
335#endif
336
337static const char *getFcFamilyForStyleHint(const QFont::StyleHint style)
338{
339 const char *stylehint = nullptr;
340 switch (style) {
341 case QFont::SansSerif:
342 stylehint = "sans-serif";
343 break;
344 case QFont::Serif:
345 stylehint = "serif";
346 break;
348 case QFont::Monospace:
349 stylehint = "monospace";
350 break;
351 case QFont::Cursive:
352 stylehint = "cursive";
353 break;
354 case QFont::Fantasy:
355 stylehint = "fantasy";
356 break;
357 default:
358 break;
359 }
360 return stylehint;
361}
362
363static inline bool requiresOpenType(int writingSystem)
364{
365 return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
366 || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
367}
368
370{
371 QString familyName;
372 QString familyNameLang;
373 FcChar8 *value = nullptr;
374 int weight_value;
375 int slant_value;
376 int spacing_value;
377 int width_value;
378 FcChar8 *file_value;
379 int indexValue;
380 FcChar8 *foundry_value;
381 FcChar8 *style_value;
382 FcBool scalable;
383 FcBool antialias;
384
385 if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch)
386 return;
387
388 familyName = QString::fromUtf8((const char *)value);
389
390 if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch)
391 familyNameLang = QString::fromUtf8((const char *)value);
392
393 slant_value = FC_SLANT_ROMAN;
394 weight_value = FC_WEIGHT_REGULAR;
395 spacing_value = FC_PROPORTIONAL;
396 file_value = nullptr;
397 indexValue = 0;
398 scalable = FcTrue;
399
400
401 if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch)
402 slant_value = FC_SLANT_ROMAN;
403 if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch)
404 weight_value = FC_WEIGHT_REGULAR;
405 if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch)
406 width_value = FC_WIDTH_NORMAL;
407 if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch)
408 spacing_value = FC_PROPORTIONAL;
409 if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch)
410 file_value = nullptr;
411 if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch)
412 indexValue = 0;
413 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
414 scalable = FcTrue;
415 if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
416 foundry_value = nullptr;
417 if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch)
418 style_value = nullptr;
419 if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch)
420 antialias = true;
421
422 QSupportedWritingSystems writingSystems;
423 FcLangSet *langset = nullptr;
424 FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset);
425 if (res == FcResultMatch) {
426 bool hasLang = false;
427#if FC_VERSION >= 20297
428 FcChar8 *cap = nullptr;
429 FcResult capRes = FcResultNoMatch;
430#endif
431 for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
432 const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j];
433 if (lang) {
434 FcLangResult langRes = FcLangSetHasLang(langset, lang);
435 if (langRes != FcLangDifferentLang) {
436#if FC_VERSION >= 20297
437 if (*capabilityForWritingSystem[j] && requiresOpenType(j)) {
438 if (cap == nullptr)
439 capRes = FcPatternGetString(pattern, FC_CAPABILITY, 0, &cap);
440 if (capRes == FcResultMatch && strstr(reinterpret_cast<const char *>(cap), capabilityForWritingSystem[j]) == nullptr)
441 continue;
442 }
443#endif
445 hasLang = true;
446 }
447 }
448 }
449 if (!hasLang)
450 // none of our known languages, add it to the other set
451 writingSystems.setSupported(QFontDatabase::Other);
452 } else {
453 // we set Other to supported for symbol fonts. It makes no
454 // sense to merge these with other ones, as they are
455 // special in a way.
456 writingSystems.setSupported(QFontDatabase::Other);
457 }
458
459 FontFile *fontFile = new FontFile;
460 fontFile->fileName = QString::fromLocal8Bit((const char *)file_value);
461 fontFile->indexValue = indexValue;
462
463 QFont::Style style = (slant_value == FC_SLANT_ITALIC)
465 : ((slant_value == FC_SLANT_OBLIQUE)
468 // Note: weight should really be an int but registerFont incorrectly uses an enum
470
471 double pixel_size = 0;
472 if (!scalable)
473 FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &pixel_size);
474
475 bool fixedPitch = spacing_value >= FC_MONO;
476 // Note: stretch should really be an int but registerFont incorrectly uses an enum
477 QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value));
478 QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString();
479
480 if (applicationFont != nullptr) {
482 properties.familyName = familyName;
483 properties.styleName = styleName;
484 properties.weight = weight;
485 properties.style = style;
486 properties.stretch = stretch;
487
488 applicationFont->properties.append(properties);
489 }
490
491 QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1StringView((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile);
492// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
493
494 for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) {
495 const QString altFamilyName = QString::fromUtf8((const char *)value);
496 // Extra family names can be aliases or subfamilies.
497 // If it is a subfamily, register it as a separate font, so only members of the subfamily are
498 // matched when the subfamily is requested.
499 QString altStyleName;
500 if (FcPatternGetString(pattern, FC_STYLE, k, &value) == FcResultMatch)
501 altStyleName = QString::fromUtf8((const char *)value);
502 else
503 altStyleName = styleName;
504
505 QString altFamilyNameLang;
506 if (FcPatternGetString(pattern, FC_FAMILYLANG, k, &value) == FcResultMatch)
507 altFamilyNameLang = QString::fromUtf8((const char *)value);
508 else
509 altFamilyNameLang = familyNameLang;
510
511 if (familyNameLang == altFamilyNameLang && altStyleName != styleName) {
512 if (applicationFont != nullptr) {
514 properties.familyName = altFamilyName;
515 properties.styleName = altStyleName;
516 properties.weight = weight;
517 properties.style = style;
518 properties.stretch = stretch;
519
520 applicationFont->properties.append(properties);
521 }
522 FontFile *altFontFile = new FontFile(*fontFile);
523 QPlatformFontDatabase::registerFont(altFamilyName, altStyleName, QLatin1StringView((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,altFontFile);
524 } else {
525 QPlatformFontDatabase::registerAliasToFontFamily(familyName, altFamilyName);
526 }
527 }
528
529}
530
532{
533 FcConfigDestroy(FcConfigGetCurrent());
534}
535
537{
538 FcInit();
539 FcFontSet *fonts;
540
541 {
542 FcObjectSet *os = FcObjectSetCreate();
543 FcPattern *pattern = FcPatternCreate();
544 const char *properties [] = {
545 FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT,
546 FC_SPACING, FC_FILE, FC_INDEX,
547 FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE,
548 FC_WIDTH, FC_FAMILYLANG,
549#if FC_VERSION >= 20297
550 FC_CAPABILITY,
551#endif
552 (const char *)nullptr
553 };
554 const char **p = properties;
555 while (*p) {
556 FcObjectSetAdd(os, *p);
557 ++p;
558 }
559 fonts = FcFontList(nullptr, pattern, os);
560 FcObjectSetDestroy(os);
561 FcPatternDestroy(pattern);
562 if (!fonts)
563 return;
564 }
565
566 for (int i = 0; i < fonts->nfont; i++)
567 populateFromPattern(fonts->fonts[i]);
568
569 FcFontSetDestroy (fonts);
570
571 struct FcDefaultFont {
572 const char *qtname;
573 const char *rawname;
574 bool fixed;
575 };
576 const FcDefaultFont defaults[] = {
577 { "Serif", "serif", false },
578 { "Sans Serif", "sans-serif", false },
579 { "Monospace", "monospace", true },
580 { nullptr, nullptr, false }
581 };
582 const FcDefaultFont *f = defaults;
583 // aliases only make sense for 'common', not for any of the specials
585 ws.setSupported(QFontDatabase::Latin);
586
587 while (f->qtname) {
588 QString familyQtName = QString::fromLatin1(f->qtname);
589 registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,ws,nullptr);
590 registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,ws,nullptr);
591 registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,ws,nullptr);
592 ++f;
593 }
594
595 //QPA has very lazy population of the font db. We want it to be initialized when
596 //QApplication is constructed, so that the population procedure can do something like this to
597 //set the default font
598// const FcDefaultFont *s = defaults;
599// QFont font("Sans Serif");
600// font.setPointSize(9);
601// QApplication::setFont(font);
602}
603
605{
606 // Clear app fonts.
607 FcConfigAppFontClear(nullptr);
608}
609
611{
612 return new QFontEngineMultiFontConfig(fontEngine, script);
613}
614
615namespace {
616QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool useXftConf)
617{
618 switch (hintingPreference) {
626 break;
627 }
628
631
632 int hint_style = 0;
633 if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultMatch) {
634 switch (hint_style) {
635 case FC_HINT_NONE:
637 case FC_HINT_SLIGHT:
639 case FC_HINT_MEDIUM:
641 case FC_HINT_FULL:
643 default:
644 Q_UNREACHABLE();
645 break;
646 }
647 }
648
649 if (useXftConf) {
650 void *hintStyleResource =
653 int hintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
654 if (hintStyle > 0)
655 return QFontEngine::HintStyle(hintStyle - 1);
656 }
657
659}
660
661QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool useXftConf)
662{
663 int subpixel = FC_RGBA_UNKNOWN;
664 if (FcPatternGetInteger(match, FC_RGBA, 0, &subpixel) == FcResultMatch) {
665 switch (subpixel) {
666 case FC_RGBA_UNKNOWN:
667 case FC_RGBA_NONE:
669 case FC_RGBA_RGB:
671 case FC_RGBA_BGR:
673 case FC_RGBA_VRGB:
675 case FC_RGBA_VBGR:
677 default:
678 Q_UNREACHABLE();
679 break;
680 }
681 }
682
683 if (useXftConf) {
684 void *subpixelTypeResource =
687 int subpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
688 if (subpixelType > 0)
689 return QFontEngine::SubpixelAntialiasingType(subpixelType - 1);
690 }
691
693}
694} // namespace
695
697{
698 if (!usrPtr)
699 return nullptr;
700
701 FontFile *fontfile = static_cast<FontFile *> (usrPtr);
703 fid.filename = QFile::encodeName(fontfile->fileName);
704 fid.index = fontfile->indexValue;
705
706 // FIXME: Unify with logic in QFontEngineFT::create()
708 engine->face_id = fid;
709
710 setupFontEngine(engine, f);
711
712 if (!engine->init(fid, engine->antialias, engine->defaultFormat) || engine->invalid()) {
713 delete engine;
714 engine = nullptr;
715 }
716
717 return engine;
718}
719
721{
722 QFontEngineFT *engine = static_cast<QFontEngineFT*>(QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference));
723 if (engine == nullptr)
724 return nullptr;
725
726 setupFontEngine(engine, engine->fontDef);
727
728 return engine;
729}
730
732{
733 QStringList fallbackFamilies;
734 FcPattern *pattern = FcPatternCreate();
735 if (!pattern)
736 return fallbackFamilies;
737
738 FcValue value;
739 value.type = FcTypeString;
740 const QByteArray cs = family.toUtf8();
741 value.u.s = (const FcChar8 *)cs.data();
742 FcPatternAdd(pattern,FC_FAMILY,value,true);
743
744 int slant_value = FC_SLANT_ROMAN;
745 if (style == QFont::StyleItalic)
746 slant_value = FC_SLANT_ITALIC;
747 else if (style == QFont::StyleOblique)
748 slant_value = FC_SLANT_OBLIQUE;
749 FcPatternAddInteger(pattern, FC_SLANT, slant_value);
750
752 if (*specialLanguages[script] != '\0') {
753 FcLangSet *ls = FcLangSetCreate();
754 FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
755 FcPatternAddLangSet(pattern, FC_LANG, ls);
756 FcLangSetDestroy(ls);
757 } else if (!family.isEmpty()) {
758 // If script is Common or Han, then it may include languages like CJK,
759 // we should attach system default language set to the pattern
760 // to obtain correct font fallback list (i.e. if LANG=zh_CN
761 // then we normally want to use a Chinese font for CJK text;
762 // while a Japanese font should be used for that if LANG=ja)
763 FcPattern *dummy = FcPatternCreate();
764 FcDefaultSubstitute(dummy);
765 FcChar8 *lang = nullptr;
766 FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang);
767 if (res == FcResultMatch)
768 FcPatternAddString(pattern, FC_LANG, lang);
769 FcPatternDestroy(dummy);
770 }
771
772 const char *stylehint = getFcFamilyForStyleHint(styleHint);
773 if (stylehint) {
774 value.u.s = (const FcChar8 *)stylehint;
775 FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
776 }
777
778 FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
779 FcDefaultSubstitute(pattern);
780
781 FcResult result = FcResultMatch;
782 FcFontSet *fontSet = FcFontSort(nullptr,pattern,FcFalse,nullptr,&result);
783 FcPatternDestroy(pattern);
784
785 if (fontSet) {
786 QDuplicateTracker<QString> duplicates(fontSet->nfont + 1);
787 (void)duplicates.hasSeen(family.toCaseFolded());
788 for (int i = 0; i < fontSet->nfont; i++) {
789 FcChar8 *value = nullptr;
790 if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
791 continue;
792 // capitalize(value);
793 const QString familyName = QString::fromUtf8((const char *)value);
794 const QString familyNameCF = familyName.toCaseFolded();
795 if (!duplicates.hasSeen(familyNameCF)) {
796 fallbackFamilies << familyName;
797 }
798 }
799 FcFontSetDestroy(fontSet);
800 }
801// qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies;
802
803 return fallbackFamilies;
804}
805
806static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
807{
808#if FC_VERSION < 20402
809 Q_UNUSED(data);
810 return FcFreeTypeQuery(file, id, blanks, count);
811#else
812 if (data.isEmpty())
813 return FcFreeTypeQuery(file, id, blanks, count);
814
815 FT_Library lib = qt_getFreetype();
816
817 FcPattern *pattern = nullptr;
818
819 FT_Face face;
820 if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
821 *count = face->num_faces;
822
823 pattern = FcFreeTypeQueryFace(face, file, id, blanks);
824
825 FT_Done_Face(face);
826 }
827
828 return pattern;
829#endif
830}
831
833{
834 QStringList families;
835
836 if (applicationFont != nullptr)
837 applicationFont->properties.clear();
838
839 FcFontSet *set = FcConfigGetFonts(nullptr, FcSetApplication);
840 if (!set) {
841 FcConfigAppFontAddFile(nullptr, (const FcChar8 *)":/non-existent");
842 set = FcConfigGetFonts(nullptr, FcSetApplication); // try again
843 if (!set)
844 return families;
845 }
846
847 int id = 0;
848 FcBlanks *blanks = FcConfigGetBlanks(nullptr);
849 int count = 0;
850
852 do {
853 pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
854 fontData, id, blanks, &count);
855 if (!pattern)
856 return families;
857
858 FcChar8 *fam = nullptr;
859 if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
860 QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
861 families << family;
862 }
863 populateFromPattern(pattern, applicationFont);
864
865 FcFontSetAdd(set, pattern);
866
867 ++id;
868 } while (id < count);
869
870 return families;
871}
872
874{
876 if (!resolved.isEmpty() && resolved != family)
877 return resolved;
878 FcPattern *pattern = FcPatternCreate();
879 if (!pattern)
880 return family;
881
882 if (!family.isEmpty()) {
883 const QByteArray cs = family.toUtf8();
884 FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData());
885 }
886 FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
887 FcDefaultSubstitute(pattern);
888
889 FcChar8 *familyAfterSubstitution = nullptr;
890 FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
891 resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
892 FcPatternDestroy(pattern);
893
894 return resolved;
895}
896
898{
899 // Hack to get system default language until FcGetDefaultLangs()
900 // is exported (https://bugs.freedesktop.org/show_bug.cgi?id=32853)
901 // or https://bugs.freedesktop.org/show_bug.cgi?id=35482 is fixed
902 FcPattern *dummy = FcPatternCreate();
903 FcDefaultSubstitute(dummy);
904 FcChar8 *lang = nullptr;
905 FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang);
906
907 FcPattern *pattern = FcPatternCreate();
908 if (res == FcResultMatch) {
909 // Make defaultFont pattern matching locale language aware, because
910 // certain FC_LANG based custom rules may happen in FcConfigSubstitute()
911 FcPatternAddString(pattern, FC_LANG, lang);
912 }
913 FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
914 FcDefaultSubstitute(pattern);
915
916 FcChar8 *familyAfterSubstitution = nullptr;
917 FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
918 QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
919 FcPatternDestroy(pattern);
920 FcPatternDestroy(dummy);
921
922 return QFont(resolved);
923}
924
925void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const
926{
927 bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
928 bool forcedAntialiasSetting = !antialias || QHighDpiScaling::isActive();
929
931 bool useXftConf = false;
932
933 if (services) {
934 const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':');
935 useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE");
936 }
937
938 if (useXftConf && !forcedAntialiasSetting) {
939 void *antialiasResource =
942 int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
943 if (antialiasingEnabled > 0)
944 antialias = antialiasingEnabled - 1;
945 }
946
948 // try and get the pattern
949 FcPattern *pattern = FcPatternCreate();
950
951 FcValue value;
952 value.type = FcTypeString;
953 QByteArray cs = fontDef.families.first().toUtf8();
954 value.u.s = (const FcChar8 *)cs.data();
955 FcPatternAdd(pattern,FC_FAMILY,value,true);
956
957 QFontEngine::FaceId fid = engine->faceId();
958
959 if (!fid.filename.isEmpty()) {
960 value.u.s = (const FcChar8 *)fid.filename.data();
961 FcPatternAdd(pattern,FC_FILE,value,true);
962
963 value.type = FcTypeInteger;
964 value.u.i = fid.index;
965 FcPatternAdd(pattern,FC_INDEX,value,true);
966 }
967
968 if (fontDef.pixelSize > 0.1)
969 FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDef.pixelSize);
970
971 FcResult result;
972
973 FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
974 FcDefaultSubstitute(pattern);
975
976 FcPattern *match = FcFontMatch(nullptr, pattern, &result);
977 if (match) {
978 engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf));
979
980 FcBool fc_autohint;
981 if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
982 engine->forceAutoHint = fc_autohint;
983
984#if defined(FT_LCD_FILTER_H)
985 int lcdFilter;
986 if (FcPatternGetInteger(match, FC_LCD_FILTER, 0, &lcdFilter) == FcResultMatch)
987 engine->lcdFilterType = lcdFilter;
988#endif
989
990 if (!forcedAntialiasSetting) {
991 FcBool fc_antialias;
992 if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch)
993 antialias = fc_antialias;
994 }
995
996 if (antialias) {
999 subpixelType = subpixelTypeFromMatch(match, useXftConf);
1000 engine->subpixelType = subpixelType;
1001
1002 format = (subpixelType == QFontEngine::Subpixel_None)
1004 : QFontEngine::Format_A32;
1005 } else
1007
1008 FcPatternDestroy(match);
1009 } else
1011
1012 FcPatternDestroy(pattern);
1013
1014 engine->antialias = antialias;
1015 engine->defaultFormat = format;
1016 engine->glyphFormat = format;
1017}
1018
std::vector< ObjCStrongReference< CBMutableService > > services
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
Script
Definition qchar.h:144
@ ScriptCount
Definition qchar.h:341
bool hasSeen(const T &s)
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
WritingSystem
\value Any \value Latin \value Greek \value Cyrillic \value Armenian \value Hebrew \value Arabic \val...
\reentrant
Definition qfont.h:20
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
Definition qfont.h:23
@ Monospace
Definition qfont.h:31
@ Serif
Definition qfont.h:25
@ Cursive
Definition qfont.h:30
@ Fantasy
Definition qfont.h:32
@ TypeWriter
Definition qfont.h:26
@ SansSerif
Definition qfont.h:24
HintingPreference
Definition qfont.h:52
@ PreferNoHinting
Definition qfont.h:54
@ PreferFullHinting
Definition qfont.h:56
@ PreferVerticalHinting
Definition qfont.h:55
@ PreferDefaultHinting
Definition qfont.h:53
Stretch
Predefined stretch values that follow the CSS naming convention.
Definition qfont.h:80
@ Unstretched
Definition qfont.h:86
@ NoSubpixelAntialias
Definition qfont.h:46
@ NoAntialias
Definition qfont.h:45
Weight
Qt uses a weighting scale from 1 to 1000 compatible with OpenType.
Definition qfont.h:60
@ DemiBold
Definition qfont.h:66
@ Thin
Definition qfont.h:61
@ ExtraBold
Definition qfont.h:68
@ Black
Definition qfont.h:69
@ Bold
Definition qfont.h:67
@ ExtraLight
Definition qfont.h:62
@ Normal
Definition qfont.h:64
@ Light
Definition qfont.h:63
@ Medium
Definition qfont.h:65
Style
This enum describes the different styles of glyphs that are used to display text.
Definition qfont.h:73
@ StyleItalic
Definition qfont.h:75
@ StyleNormal
Definition qfont.h:74
@ StyleOblique
Definition qfont.h:76
QFontEngineMulti * fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) override
Returns a multi font engine in the specified script to encapsulate fontEngine with the option to fall...
void populateFontDatabase() override
This function is called once at startup by Qt's internal font database.
QString resolveFontFamilyAlias(const QString &family) const override
Resolve alias to actual font family names.
QFont defaultFont() const override
Returns the default system font.
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont=nullptr) override
Adds an application font described by the font contained supplied fontData or using the font containe...
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
void invalidate() override
This function is called whenever the font database is invalidated.
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
static QPlatformIntegration * platformIntegration()
static QPlatformNativeInterface * platformNativeInterface()
QScreen * primaryScreen
the primary (or default) screen of the application.
static bool isActive()
Definition qlist.h:74
virtual QString resolveFontFamilyAlias(const QString &family) const
Resolve alias to actual font family names.
static void registerAliasToFontFamily(const QString &familyName, const QString &alias)
Helper function that register the alias for the familyName.
static void registerFont(const QString &familyname, const QString &stylename, const QString &foundryname, QFont::Weight weight, QFont::Style style, QFont::Stretch stretch, bool antialiased, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *handle)
Registers a font with the given set of attributes describing the font's foundry, family name,...
virtual QPlatformServices * services() const
virtual void * nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
The QPlatformServices provides the backend for desktop-related functionality.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
QString toCaseFolded() const &
Definition qstring.h:376
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QByteArray toUtf8() const &
Definition qstring.h:563
The QSupportedWritingSystems class is used when registering fonts with the internal Qt fontdatabase.
void setSupported(QFontDatabase::WritingSystem, bool supported=true)
Sets or clears support for the specified writingSystem based on the value given by support.
Combined button and popup list for selecting options.
static const QCssKnownValue properties[NumProperties - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define QFONT_WEIGHT_MAX
Definition qfont_p.h:34
static int stretchFromFcWidth(int fcwidth)
static QT_BEGIN_NAMESPACE int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, int qtLower, int qtUpper)
static int weightFromFcWeight(int fcweight)
static FcPattern * queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
static bool requiresOpenType(int writingSystem)
static const char languageForWritingSystem[][6]
static const char specialLanguages[][6]
static void populateFromPattern(FcPattern *pattern, QFontDatabasePrivate::ApplicationFont *applicationFont=nullptr)
static const char * getFcFamilyForStyleHint(const QFont::StyleHint style)
FT_Library qt_getFreetype()
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLenum face
GLfloat GLfloat f
GLuint GLuint GLfloat weight
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
GLenum GLsizeiptr const void * fontData
GLuint res
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLubyte * pattern
GLenum cap
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
ptrdiff_t qintptr
Definition qtypes.h:71
struct _FcPattern FcPattern
QFuture< QSet< QChar > > set
[10]
QFile file
[0]
QFile defaults(defaultsPath)
QJSEngine engine
[0]
uint hintingPreference
Definition qfont_p.h:66
uint styleStrategy
Definition qfont_p.h:63
qreal pixelSize
Definition qfont_p.h:60
QStringList families
Definition qfont_p.h:54
bool contains(const AT &t) const noexcept
Definition qlist.h:44