Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qfontdatabase.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfontdatabase.h"
5#include "qfontdatabase_p.h"
6#include "qloggingcategory.h"
7#include "qalgorithms.h"
8#include "qguiapplication.h"
9#include "qvarlengtharray.h" // here or earlier - workaround for VC++6
10#include "qthread.h"
11#include "qmutex.h"
12#include "qfile.h"
13#include "qfileinfo.h"
14#include "qfontengine_p.h"
15#include <qpa/qplatformintegration.h>
16
17#include <QtGui/private/qguiapplication_p.h>
18#include <qpa/qplatformfontdatabase.h>
19#include <qpa/qplatformtheme.h>
20
21#include <QtCore/qcache.h>
22#include <QtCore/qmath.h>
23
24#include <stdlib.h>
25#include <algorithm>
26
27#include <qtgui_tracepoints_p.h>
28
29#ifdef Q_OS_WIN
30#include <QtGui/private/qwindowsfontdatabasebase_p.h>
31#endif
32
34
35using namespace Qt::StringLiterals;
36
37Q_LOGGING_CATEGORY(lcFontDb, "qt.text.font.db")
38Q_LOGGING_CATEGORY(lcFontMatch, "qt.text.font.match")
39
40#define SMOOTH_SCALABLE 0xffff
41
42#if defined(QT_BUILD_INTERNAL)
43bool qt_enable_test_font = false;
44
45Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value)
46{
47 qt_enable_test_font = value;
48}
49#endif
50
51Q_TRACE_POINT(qtgui, QFontDatabase_loadEngine, const QString &families, int pointSize);
52Q_TRACE_POINT(qtgui, QFontDatabasePrivate_addAppFont, const QString &fileName);
53Q_TRACE_POINT(qtgui, QFontDatabase_addApplicationFont, const QString &fileName);
54Q_TRACE_POINT(qtgui, QFontDatabase_load, const QString &family, int pointSize);
55
56static int getFontWeight(const QString &weightString)
57{
58 QString s = weightString.toLower();
59
60 // Order here is important. We want to match the common cases first, but we
61 // must also take care to acknowledge the cost of our tests.
62 //
63 // As a result, we test in two orders; the order of commonness, and the
64 // order of "expense".
65 //
66 // A simple string test is the cheapest, so let's do that first.
67 // Test in decreasing order of commonness
68 if (s == "normal"_L1 || s == "regular"_L1)
69 return QFont::Normal;
70 if (s == "bold"_L1)
71 return QFont::Bold;
72 if (s == "semibold"_L1 || s == "semi bold"_L1 || s == "demibold"_L1 || s == "demi bold"_L1)
73 return QFont::DemiBold;
74 if (s == "medium"_L1)
75 return QFont::Medium;
76 if (s == "black"_L1)
77 return QFont::Black;
78 if (s == "light"_L1)
79 return QFont::Light;
80 if (s == "thin"_L1)
81 return QFont::Thin;
82 const QStringView s2 = QStringView{s}.mid(2);
83 if (s.startsWith("ex"_L1) || s.startsWith("ul"_L1)) {
84 if (s2 == "tralight"_L1 || s == "tra light"_L1)
85 return QFont::ExtraLight;
86 if (s2 == "trabold"_L1 || s2 == "tra bold"_L1)
87 return QFont::ExtraBold;
88 }
89
90 // Next up, let's see if contains() matches: slightly more expensive, but
91 // still fast enough.
92 if (s.contains("bold"_L1)) {
93 if (s.contains("demi"_L1))
94 return QFont::DemiBold;
95 return QFont::Bold;
96 }
97 if (s.contains("thin"_L1))
98 return QFont::Thin;
99 if (s.contains("light"_L1))
100 return QFont::Light;
101 if (s.contains("black"_L1))
102 return QFont::Black;
103
104 // Now, we perform string translations & comparisons with those.
105 // These are (very) slow compared to simple string ops, so we do these last.
106 // As using translated values for such things is not very common, this should
107 // not be too bad.
108 if (s.compare(QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight"), Qt::CaseInsensitive) == 0)
109 return QFont::Normal;
110 const QString translatedBold = QCoreApplication::translate("QFontDatabase", "Bold").toLower();
111 if (s == translatedBold)
112 return QFont::Bold;
113 if (s.compare(QCoreApplication::translate("QFontDatabase", "Demi Bold"), Qt::CaseInsensitive) == 0)
114 return QFont::DemiBold;
115 if (s.compare(QCoreApplication::translate("QFontDatabase", "Medium", "The Medium font weight"), Qt::CaseInsensitive) == 0)
116 return QFont::Medium;
117 if (s.compare(QCoreApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
118 return QFont::Black;
119 const QString translatedLight = QCoreApplication::translate("QFontDatabase", "Light").toLower();
120 if (s == translatedLight)
121 return QFont::Light;
122 if (s.compare(QCoreApplication::translate("QFontDatabase", "Thin"), Qt::CaseInsensitive) == 0)
123 return QFont::Thin;
124 if (s.compare(QCoreApplication::translate("QFontDatabase", "Extra Light"), Qt::CaseInsensitive) == 0)
125 return QFont::ExtraLight;
126 if (s.compare(QCoreApplication::translate("QFontDatabase", "Extra Bold"), Qt::CaseInsensitive) == 0)
127 return QFont::ExtraBold;
128
129 // And now the contains() checks for the translated strings.
130 //: The word for "Extra" as in "Extra Bold, Extra Thin" used as a pattern for string searches
131 const QString translatedExtra = QCoreApplication::translate("QFontDatabase", "Extra").toLower();
132 if (s.contains(translatedBold)) {
133 //: The word for "Demi" as in "Demi Bold" used as a pattern for string searches
134 QString translatedDemi = QCoreApplication::translate("QFontDatabase", "Demi").toLower();
135 if (s .contains(translatedDemi))
136 return QFont::DemiBold;
137 if (s.contains(translatedExtra))
138 return QFont::ExtraBold;
139 return QFont::Bold;
140 }
141
142 if (s.contains(translatedLight)) {
143 if (s.contains(translatedExtra))
144 return QFont::ExtraLight;
145 return QFont::Light;
146 }
147 return QFont::Normal;
148}
149
150
152 : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0)
153{
154 weight = getFontWeight(styleString);
155
156 if (!styleString.isEmpty()) {
157 // First the straightforward no-translation checks, these are fast.
158 if (styleString.contains("Italic"_L1))
160 else if (styleString.contains("Oblique"_L1))
162
163 // Then the translation checks. These aren't as fast.
164 else if (styleString.contains(QCoreApplication::translate("QFontDatabase", "Italic")))
166 else if (styleString.contains(QCoreApplication::translate("QFontDatabase", "Oblique")))
168 }
169}
170
172{
173 for (int i = 0; i < count; i++) {
174 if (pixelSizes[i].pixelSize == size)
175 return pixelSizes + i;
176 }
177 if (!add)
178 return nullptr;
179
180 if (!pixelSizes) {
181 // Most style have only one font size, we avoid waisting memory
182 QtFontSize *newPixelSizes = (QtFontSize *)malloc(sizeof(QtFontSize));
183 Q_CHECK_PTR(newPixelSizes);
184 pixelSizes = newPixelSizes;
185 } else if (!(count % 8) || count == 1) {
186 QtFontSize *newPixelSizes = (QtFontSize *)
187 realloc(pixelSizes,
188 (((count+8) >> 3) << 3) * sizeof(QtFontSize));
189 Q_CHECK_PTR(newPixelSizes);
190 pixelSizes = newPixelSizes;
191 }
193 pixelSizes[count].handle = nullptr;
194 return pixelSizes + (count++);
195}
196
198{
199 int pos = 0;
200 for (; pos < count; pos++) {
201 bool hasStyleName = !styleName.isEmpty(); // search styleName first if available
202 if (hasStyleName && !styles[pos]->styleName.isEmpty()) {
203 if (styles[pos]->styleName == styleName)
204 return styles[pos];
205 } else {
206 if (styles[pos]->key == key)
207 return styles[pos];
208 }
209 }
210 if (!create)
211 return nullptr;
212
213// qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos);
214 if (!(count % 8)) {
215 QtFontStyle **newStyles = (QtFontStyle **)
216 realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *));
217 Q_CHECK_PTR(newStyles);
218 styles = newStyles;
219 }
220
221 QtFontStyle *style = new QtFontStyle(key);
222 style->styleName = styleName;
223 styles[pos] = style;
224 count++;
225 return styles[pos];
226}
227
229{
230 if (f.isNull() && count == 1)
231 return foundries[0];
232
233 for (int i = 0; i < count; i++) {
234 if (foundries[i]->name.compare(f, Qt::CaseInsensitive) == 0)
235 return foundries[i];
236 }
237 if (!create)
238 return nullptr;
239
240 if (!(count % 8)) {
241 QtFontFoundry **newFoundries = (QtFontFoundry **)
242 realloc(foundries,
243 (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *));
244 Q_CHECK_PTR(newFoundries);
245 foundries = newFoundries;
246 }
247
248 foundries[count] = new QtFontFoundry(f);
249 return foundries[count++];
250}
251
252static inline bool equalsCaseInsensitive(const QString &a, const QString &b)
253{
254 return a.size() == b.size() && a.compare(b, Qt::CaseInsensitive) == 0;
255}
256
257bool QtFontFamily::matchesFamilyName(const QString &familyName) const
258{
259 return equalsCaseInsensitive(name, familyName) || aliases.contains(familyName, Qt::CaseInsensitive);
260}
261
263{
264 if (populated)
265 return true;
266
267 QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamily(name);
268 return populated;
269}
270
272{
273 while (count--)
274 delete families[count];
275 ::free(families);
276 families = nullptr;
277 count = 0;
278
279 for (auto &font : applicationFonts)
280 font.properties.clear(); // Unpopulate
281
282 populated = false;
283 // don't clear the memory fonts!
284}
285
287{
288 qCDebug(lcFontDb) << "Invalidating font database";
289
290 QFontCache::instance()->clear();
291
292 fallbacksCache.clear();
293 clearFamilies();
294 QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate();
295 emit qGuiApp->fontDatabaseChanged();
296}
297
299{
300 QtFontFamily *fam = nullptr;
301
302 int low = 0;
303 int high = count;
304 int pos = count / 2;
305 int res = 1;
306 if (count) {
307 while ((res = families[pos]->name.compare(f, Qt::CaseInsensitive)) && pos != low) {
308 if (res > 0)
309 high = pos;
310 else
311 low = pos;
312 pos = (high + low) / 2;
313 }
314 if (!res)
315 fam = families[pos];
316 }
317
318 if (!fam && (flags & EnsureCreated)) {
319 if (res < 0)
320 pos++;
321
322 // qDebug() << "adding family " << f.toLatin1() << " at " << pos << " total=" << count;
323 if (!(count % 8)) {
324 QtFontFamily **newFamilies = (QtFontFamily **)
325 realloc(families,
326 (((count+8) >> 3) << 3) * sizeof(QtFontFamily *));
327 Q_CHECK_PTR(newFamilies);
328 families = newFamilies;
329 }
330
331 QtFontFamily *family = new QtFontFamily(f);
332 memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *));
333 families[pos] = family;
334 count++;
335
336 fam = families[pos];
337 }
338
339 if (fam && (flags & EnsurePopulated)) {
340 if (!fam->ensurePopulated())
341 return nullptr;
342 }
343
344 return fam;
345}
346
347
348
349static const int scriptForWritingSystem[] = {
350 QChar::Script_Common, // Any
351 QChar::Script_Latin, // Latin
352 QChar::Script_Greek, // Greek
353 QChar::Script_Cyrillic, // Cyrillic
354 QChar::Script_Armenian, // Armenian
355 QChar::Script_Hebrew, // Hebrew
356 QChar::Script_Arabic, // Arabic
357 QChar::Script_Syriac, // Syriac
358 QChar::Script_Thaana, // Thaana
359 QChar::Script_Devanagari, // Devanagari
360 QChar::Script_Bengali, // Bengali
361 QChar::Script_Gurmukhi, // Gurmukhi
362 QChar::Script_Gujarati, // Gujarati
363 QChar::Script_Oriya, // Oriya
364 QChar::Script_Tamil, // Tamil
365 QChar::Script_Telugu, // Telugu
366 QChar::Script_Kannada, // Kannada
367 QChar::Script_Malayalam, // Malayalam
368 QChar::Script_Sinhala, // Sinhala
369 QChar::Script_Thai, // Thai
370 QChar::Script_Lao, // Lao
371 QChar::Script_Tibetan, // Tibetan
372 QChar::Script_Myanmar, // Myanmar
373 QChar::Script_Georgian, // Georgian
374 QChar::Script_Khmer, // Khmer
375 QChar::Script_Han, // SimplifiedChinese
376 QChar::Script_Han, // TraditionalChinese
377 QChar::Script_Han, // Japanese
378 QChar::Script_Hangul, // Korean
379 QChar::Script_Latin, // Vietnamese
380 QChar::Script_Common, // Symbol
381 QChar::Script_Ogham, // Ogham
382 QChar::Script_Runic, // Runic
383 QChar::Script_Nko // Nko
384};
385
387
389{
390 return scriptForWritingSystem[writingSystem];
391}
392
393
400static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSystem)
401{
402 Q_ASSERT(family != nullptr);
403 Q_ASSERT(writingSystem != QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount);
404
405 size_t ws = writingSystem;
406 do {
407 if ((family->writingSystems[ws] & QtFontFamily::Supported) != 0)
408 return true;
409 } while (writingSystem >= QFontDatabase::SimplifiedChinese && writingSystem <= QFontDatabase::Japanese && ++ws <= QFontDatabase::Japanese);
410
411 return false;
412}
413
420
430static void parseFontName(const QString &name, QString &foundry, QString &family)
431{
432 int i = name.indexOf(u'[');
433 int li = name.lastIndexOf(u']');
434 if (i >= 0 && li >= 0 && i < li) {
435 foundry = name.mid(i + 1, li - i - 1);
436 if (i > 0 && name[i - 1] == u' ')
437 i--;
438 family = name.left(i);
439 } else {
440 foundry.clear();
441 family = name;
442 }
443
444 // capitalize the family/foundry names
445 bool space = true;
446 QChar *s = family.data();
447 int len = family.size();
448 while(len--) {
449 if (space) *s = s->toUpper();
450 space = s->isSpace();
451 ++s;
452 }
453
454 space = true;
455 s = foundry.data();
456 len = foundry.size();
457 while(len--) {
458 if (space) *s = s->toUpper();
459 space = s->isSpace();
460 ++s;
461 }
462}
463
464
473
474static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi)
475{
476 QString family;
477 family = desc.family->name;
478 if (! desc.foundry->name.isEmpty() && desc.family->count > 1)
479 family += " ["_L1 + desc.foundry->name + u']';
480 fontDef->families = QStringList(family);
481
482 if (desc.style->smoothScalable
483 || QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable()
484 || (desc.style->bitmapScalable && (request.styleStrategy & QFont::PreferMatch))) {
485 fontDef->pixelSize = request.pixelSize;
486 } else {
487 fontDef->pixelSize = desc.size->pixelSize;
488 }
489 fontDef->pointSize = request.pointSize;
490
491 fontDef->styleHint = request.styleHint;
492 fontDef->styleStrategy = request.styleStrategy;
493
494 if (!multi)
495 fontDef->weight = desc.style->key.weight;
496 if (!multi)
497 fontDef->style = desc.style->key.style;
498 fontDef->fixedPitch = desc.family->fixedPitch;
499 fontDef->ignorePitch = false;
500}
501
503{
504 // list of families to try
505 QStringList family_list;
506
507 family_list << req.families;
508 // append the substitute list for each family in family_list
509 for (int i = 0, size = family_list.size(); i < size; ++i)
510 family_list += QFont::substitutes(family_list.at(i));
511
512 return family_list;
513}
514
515Q_GLOBAL_STATIC(QRecursiveMutex, fontDatabaseMutex)
516
517// used in qguiapplication.cpp
519{
521 db->fallbacksCache.clear();
522 db->clearFamilies();
523}
524
525// used in qfont.cpp
527{
528 return fontDatabaseMutex();
529}
530
532{
533 static QFontDatabasePrivate instance;
534 return &instance;
535}
536
537void qt_registerFont(const QString &familyName, const QString &stylename,
538 const QString &foundryname, int weight,
539 QFont::Style style, int stretch, bool antialiased,
540 bool scalable, int pixelSize, bool fixedPitch,
541 const QSupportedWritingSystems &writingSystems, void *handle)
542{
544 qCDebug(lcFontDb) << "Adding font: familyName" << familyName << "stylename" << stylename << "weight" << weight
545 << "style" << style << "pixelSize" << pixelSize << "antialiased" << antialiased << "fixed" << fixedPitch;
546 QtFontStyle::Key styleKey;
547 styleKey.style = style;
548 styleKey.weight = weight;
549 styleKey.stretch = stretch;
550 QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::EnsureCreated);
551 f->fixedPitch = fixedPitch;
552
553 for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
554 if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
555 f->writingSystems[i] = QtFontFamily::Supported;
556 }
557
558 QtFontFoundry *foundry = f->foundry(foundryname, true);
559 QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
560 fontStyle->smoothScalable = scalable;
561 fontStyle->antialiased = antialiased;
563 if (size->handle) {
565 if (integration)
566 integration->fontDatabase()->releaseHandle(size->handle);
567 }
568 size->handle = handle;
569 f->populated = true;
570}
571
572void qt_registerFontFamily(const QString &familyName)
573{
574 qCDebug(lcFontDb) << "Registering family" << familyName;
575
576 // Create uninitialized/unpopulated family
578}
579
580void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
581{
582 if (alias.isEmpty())
583 return;
584
585 qCDebug(lcFontDb) << "Registering alias" << alias << "to family" << familyName;
586
588 QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
589 if (!f)
590 return;
591
592 if (f->aliases.contains(alias, Qt::CaseInsensitive))
593 return;
594
595 f->aliases.push_back(alias);
596}
597
599{
600 if (!alias.isEmpty()) {
601 const auto *d = QFontDatabasePrivate::instance();
602 for (int i = 0; i < d->count; ++i)
603 if (d->families[i]->matchesFamilyName(alias))
604 return d->families[i]->name;
605 }
606 return alias;
607}
608
609bool qt_isFontFamilyPopulated(const QString &familyName)
610{
612 QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
613 return f != nullptr && f->populated;
614}
615
623QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
624{
625 Q_UNUSED(family);
626 Q_UNUSED(styleHint);
627
628 QStringList preferredFallbacks;
629 QStringList otherFallbacks;
630
631 auto writingSystem = qt_writing_system_for_script(script);
632 if (writingSystem >= QFontDatabase::WritingSystemsCount)
633 writingSystem = QFontDatabase::Any;
634
636 for (int i = 0; i < db->count; ++i) {
637 QtFontFamily *f = db->families[i];
638
639 f->ensurePopulated();
640
641 if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(f, writingSystem))
642 continue;
643
644 for (int j = 0; j < f->count; ++j) {
645 QtFontFoundry *foundry = f->foundries[j];
646
647 for (int k = 0; k < foundry->count; ++k) {
648 QString name = foundry->name.isEmpty()
649 ? f->name
650 : f->name + " ["_L1 + foundry->name + u']';
651 if (style == foundry->styles[k]->key.style)
652 preferredFallbacks.append(name);
653 else
654 otherFallbacks.append(name);
655 }
656 }
657 }
658
659 return preferredFallbacks + otherFallbacks;
660}
661
662static QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
663{
664 QMutexLocker locker(fontDatabaseMutex());
666
667 const QtFontFallbacksCacheKey cacheKey = { family, style, styleHint, script };
668
669 if (const QStringList *fallbacks = db->fallbacksCache.object(cacheKey))
670 return *fallbacks;
671
672 // make sure that the db has all fallback families
673 QStringList userFallbacks = db->applicationFallbackFontFamilies.value(script == QChar::Script_Common ? QChar::Script_Latin : script);
674 QStringList retList = userFallbacks + QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
675
676 QStringList::iterator i;
677 for (i = retList.begin(); i != retList.end(); ++i) {
678 bool contains = false;
679 for (int j = 0; j < db->count; j++) {
680 if (db->families[j]->matchesFamilyName(*i)) {
681 contains = true;
682 break;
683 }
684 }
685 if (!contains) {
686 i = retList.erase(i);
687 --i;
688 }
689 }
690
691 db->fallbacksCache.insert(cacheKey, new QStringList(retList));
692
693 return retList;
694}
695
696QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
697{
698 QMutexLocker locker(fontDatabaseMutex());
699 return fallbacksForFamily(family, style, styleHint, script);
700}
701
702QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script,
703 const QFontDef &request,
704 QtFontFamily *family, QtFontFoundry *foundry,
705 QtFontStyle *style, QtFontSize *size)
706{
707 Q_UNUSED(foundry);
708
709 Q_ASSERT(size);
711 int pixelSize = size->pixelSize;
713 || pfdb->fontsAlwaysScalable()) {
714 pixelSize = request.pixelSize;
715 }
716
717 QFontDef def = request;
718 def.pixelSize = pixelSize;
719
720 QFontCache *fontCache = QFontCache::instance();
721
722 QFontCache::Key key(def,script);
723 QFontEngine *engine = fontCache->findEngine(key);
724 if (!engine) {
725 const bool cacheForCommonScript = script != QChar::Script_Common
727
728 if (Q_LIKELY(cacheForCommonScript)) {
729 // fast path: check if engine was loaded for another script
730 key.script = QChar::Script_Common;
731 engine = fontCache->findEngine(key);
732 key.script = script;
733 if (engine) {
734 // Also check for OpenType tables when using complex scripts
735 if (Q_UNLIKELY(!engine->supportsScript(QChar::Script(script)))) {
736 qWarning(" OpenType support missing for \"%s\", script %d",
737 qPrintable(def.families.constFirst()), script);
738 return nullptr;
739 }
740
741 engine->isSmoothlyScalable = style->smoothScalable;
742 fontCache->insertEngine(key, engine);
743 return engine;
744 }
745 }
746
747 // To avoid synthesized stretch we need a matching stretch to be 100 after this point.
748 // If stretch didn't match exactly we need to calculate the new stretch factor.
749 // This only done if not matched by styleName.
750 if (style->key.stretch != 0 && request.stretch != 0
751 && (request.styleName.isEmpty() || request.styleName != style->styleName)) {
752 def.stretch = (request.stretch * 100 + style->key.stretch / 2) / style->key.stretch;
753 } else if (request.stretch == QFont::AnyStretch) {
754 def.stretch = 100;
755 }
756
757 engine = pfdb->fontEngine(def, size->handle);
758 if (engine) {
759 // Also check for OpenType tables when using complex scripts
760 if (!engine->supportsScript(QChar::Script(script))) {
761 qWarning(" OpenType support missing for \"%s\", script %d",
762 +qPrintable(def.families.constFirst()), script);
763 if (engine->ref.loadRelaxed() == 0)
764 delete engine;
765 return nullptr;
766 }
767
768 engine->isSmoothlyScalable = style->smoothScalable;
769 fontCache->insertEngine(key, engine);
770
771 if (Q_LIKELY(cacheForCommonScript && !engine->symbol)) {
772 // cache engine for Common script as well
773 key.script = QChar::Script_Common;
774 if (!fontCache->findEngine(key))
775 fontCache->insertEngine(key, engine);
776 }
777 }
778 }
779 return engine;
780}
781
782QFontEngine *QFontDatabasePrivate::loadEngine(int script, const QFontDef &request,
783 QtFontFamily *family, QtFontFoundry *foundry,
784 QtFontStyle *style, QtFontSize *size)
785{
786 QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size);
787
788 if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
789 Q_TRACE(QFontDatabase_loadEngine, request.families.join(QLatin1Char(';')), request.pointSize);
790
792 QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script));
793 if (!request.fallBackFamilies.isEmpty()) {
794 QStringList fallbacks = request.fallBackFamilies;
795
796 QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
797 if (styleHint == QFont::AnyStyle && request.fixedPitch)
798 styleHint = QFont::TypeWriter;
799
800 fallbacks += fallbacksForFamily(family->name, QFont::Style(style->key.style), styleHint, QChar::Script(script));
801
802 pfMultiEngine->setFallbackFamiliesList(fallbacks);
803 }
804 engine = pfMultiEngine;
805
806 // Cache Multi font engine as well in case we got the single
807 // font engine when we are actually looking for a Multi one
808 QFontCache::Key key(request, script, 1);
809 QFontCache::instance()->insertEngine(key, engine);
810 }
811
812 return engine;
813}
814
816{
817 while (count) {
818 // bitfield count-- in while condition does not work correctly in mwccsym2
819 count--;
821 if (integration)
822 integration->fontDatabase()->releaseHandle(pixelSizes[count].handle);
823 }
824
825 free(pixelSizes);
826}
827
828static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey,
829 const QString &styleName = QString())
830{
831 int best = 0;
832 int dist = 0xffff;
833
834 for ( int i = 0; i < foundry->count; i++ ) {
835 QtFontStyle *style = foundry->styles[i];
836
837 if (!styleName.isEmpty() && styleName == style->styleName) {
838 dist = 0;
839 best = i;
840 break;
841 }
842
843 int d = qAbs( (int(styleKey.weight) - int(style->key.weight)) / 10 );
844
845 if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
846 d += qAbs( styleKey.stretch - style->key.stretch );
847 }
848
849 if (styleKey.style != style->key.style) {
850 if (styleKey.style != QFont::StyleNormal && style->key.style != QFont::StyleNormal)
851 // one is italic, the other oblique
852 d += 0x0001;
853 else
854 d += 0x1000;
855 }
856
857 if ( d < dist ) {
858 best = i;
859 dist = d;
860 }
861 }
862
863 qCDebug(lcFontMatch, " best style has distance 0x%x", dist );
864 return foundry->styles[best];
865}
866
867
868unsigned int QFontDatabasePrivate::bestFoundry(int script, unsigned int score, int styleStrategy,
869 const QtFontFamily *family, const QString &foundry_name,
870 QtFontStyle::Key styleKey, int pixelSize, char pitch,
871 QtFontDesc *desc, const QString &styleName)
872{
873 Q_UNUSED(script);
874 Q_UNUSED(pitch);
875
876 desc->foundry = nullptr;
877 desc->style = nullptr;
878 desc->size = nullptr;
879
880
881 qCDebug(lcFontMatch, " REMARK: looking for best foundry for family '%s' [%d]", family->name.toLatin1().constData(), family->count);
882
883 for (int x = 0; x < family->count; ++x) {
884 QtFontFoundry *foundry = family->foundries[x];
885 if (!foundry_name.isEmpty() && foundry->name.compare(foundry_name, Qt::CaseInsensitive) != 0)
886 continue;
887
888 qCDebug(lcFontMatch, " looking for matching style in foundry '%s' %d",
889 foundry->name.isEmpty() ? "-- none --" : foundry->name.toLatin1().constData(), foundry->count);
890
891 QtFontStyle *style = bestStyle(foundry, styleKey, styleName);
892
893 if (!style->smoothScalable && (styleStrategy & QFont::ForceOutline)) {
894 qCDebug(lcFontMatch, " ForceOutline set, but not smoothly scalable");
895 continue;
896 }
897
898 int px = -1;
899 QtFontSize *size = nullptr;
900
901 // 1. see if we have an exact matching size
902 if (!(styleStrategy & QFont::ForceOutline)) {
903 size = style->pixelSize(pixelSize);
904 if (size) {
905 qCDebug(lcFontMatch, " found exact size match (%d pixels)", size->pixelSize);
906 px = size->pixelSize;
907 }
908 }
909
910 // 2. see if we have a smoothly scalable font
911 if (!size && style->smoothScalable && ! (styleStrategy & QFont::PreferBitmap)) {
913 if (size) {
914 qCDebug(lcFontMatch, " found smoothly scalable font (%d pixels)", pixelSize);
915 px = pixelSize;
916 }
917 }
918
919 // 3. see if we have a bitmap scalable font
920 if (!size && style->bitmapScalable && (styleStrategy & QFont::PreferMatch)) {
921 size = style->pixelSize(0);
922 if (size) {
923 qCDebug(lcFontMatch, " found bitmap scalable font (%d pixels)", pixelSize);
924 px = pixelSize;
925 }
926 }
927
928
929 // 4. find closest size match
930 if (! size) {
931 unsigned int distance = ~0u;
932 for (int x = 0; x < style->count; ++x) {
933
934 unsigned int d;
935 if (style->pixelSizes[x].pixelSize < pixelSize) {
936 // penalize sizes that are smaller than the
937 // requested size, due to truncation from floating
938 // point to integer conversions
939 d = pixelSize - style->pixelSizes[x].pixelSize + 1;
940 } else {
941 d = style->pixelSizes[x].pixelSize - pixelSize;
942 }
943
944 if (d < distance) {
945 distance = d;
946 size = style->pixelSizes + x;
947 qCDebug(lcFontMatch, " best size so far: %3d (%d)", size->pixelSize, pixelSize);
948 }
949 }
950
951 if (!size) {
952 qCDebug(lcFontMatch, " no size supports the script we want");
953 continue;
954 }
955
956 if (style->bitmapScalable && ! (styleStrategy & QFont::PreferQuality) &&
957 (distance * 10 / pixelSize) >= 2) {
958 // the closest size is not close enough, go ahead and
959 // use a bitmap scaled font
960 size = style->pixelSize(0);
961 px = pixelSize;
962 } else {
963 px = size->pixelSize;
964 }
965 }
966
967
968 unsigned int this_score = 0x0000;
969 enum {
970 PitchMismatch = 0x4000,
971 StyleMismatch = 0x2000,
972 BitmapScaledPenalty = 0x1000
973 };
974 if (pitch != '*') {
975 if ((pitch == 'm' && !family->fixedPitch)
976 || (pitch == 'p' && family->fixedPitch))
977 this_score += PitchMismatch;
978 }
979 if (styleKey != style->key)
980 this_score += StyleMismatch;
981 if (!style->smoothScalable && px != size->pixelSize) // bitmap scaled
982 this_score += BitmapScaledPenalty;
983 if (px != pixelSize) // close, but not exact, size match
984 this_score += qAbs(px - pixelSize);
985
986 if (this_score < score) {
987 qCDebug(lcFontMatch, " found a match: score %x best score so far %x",
988 this_score, score);
989
990 score = this_score;
991 desc->foundry = foundry;
992 desc->style = style;
993 desc->size = size;
994 } else {
995 qCDebug(lcFontMatch, " score %x no better than best %x", this_score, score);
996 }
997 }
998
999 return score;
1000}
1001
1002static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
1003{
1004 if (familyName.isEmpty())
1005 return true;
1006 return f->matchesFamilyName(familyName);
1007}
1008
1014int QFontDatabasePrivate::match(int script, const QFontDef &request, const QString &family_name,
1015 const QString &foundry_name, QtFontDesc *desc, const QList<int> &blacklistedFamilies,
1016 unsigned int *resultingScore)
1017{
1018 int result = -1;
1019
1020 QtFontStyle::Key styleKey;
1021 styleKey.style = request.style;
1022 styleKey.weight = request.weight;
1023 // Prefer a stretch closest to 100.
1024 styleKey.stretch = request.stretch ? request.stretch : 100;
1025 char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
1026
1027
1028 qCDebug(lcFontMatch, "QFontDatabasePrivate::match\n"
1029 " request:\n"
1030 " family: %s [%s], script: %d\n"
1031 " styleName: %s\n"
1032 " weight: %d, style: %d\n"
1033 " stretch: %d\n"
1034 " pixelSize: %g\n"
1035 " pitch: %c",
1036 family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
1037 foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(), script,
1038 request.styleName.isEmpty() ? "-- any --" : request.styleName.toLatin1().constData(),
1039 request.weight, request.style, request.stretch, request.pixelSize, pitch);
1040
1041 desc->family = nullptr;
1042 desc->foundry = nullptr;
1043 desc->style = nullptr;
1044 desc->size = nullptr;
1045
1046 unsigned int score = ~0u;
1047
1048 QMutexLocker locker(fontDatabaseMutex());
1050
1051 auto writingSystem = qt_writing_system_for_script(script);
1052 if (writingSystem >= QFontDatabase::WritingSystemsCount)
1053 writingSystem = QFontDatabase::Any;
1054
1056 for (int x = 0; x < db->count; ++x) {
1057 if (blacklistedFamilies.contains(x))
1058 continue;
1059 QtFontDesc test;
1060 test.family = db->families[x];
1061
1062 if (!matchFamilyName(family_name, test.family))
1063 continue;
1064 if (!test.family->ensurePopulated())
1065 continue;
1066
1067 // Check if family is supported in the script we want
1068 if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(test.family, writingSystem))
1069 continue;
1070
1071 // as we know the script is supported, we can be sure
1072 // to find a matching font here.
1073 unsigned int newscore =
1074 bestFoundry(script, score, request.styleStrategy,
1075 test.family, foundry_name, styleKey, request.pixelSize, pitch,
1076 &test, request.styleName);
1077 if (test.foundry == nullptr && !foundry_name.isEmpty()) {
1078 // the specific foundry was not found, so look for
1079 // any foundry matching our requirements
1080 newscore = bestFoundry(script, score, request.styleStrategy, test.family,
1081 QString(), styleKey, request.pixelSize,
1082 pitch, &test, request.styleName);
1083 }
1084
1085 if (newscore < score) {
1086 result = x;
1087 score = newscore;
1088 *desc = test;
1089 }
1090 if (newscore < 10) // xlfd instead of FT... just accept it
1091 break;
1092 }
1093
1094 if (resultingScore != nullptr)
1095 *resultingScore = score;
1096
1097 return result;
1098}
1099
1101{
1103 if (weight > QFont::Normal) {
1104 if (weight >= QFont::Black)
1105 result = QCoreApplication::translate("QFontDatabase", "Black");
1106 else if (weight >= QFont::ExtraBold)
1107 result = QCoreApplication::translate("QFontDatabase", "Extra Bold");
1108 else if (weight >= QFont::Bold)
1109 result = QCoreApplication::translate("QFontDatabase", "Bold");
1110 else if (weight >= QFont::DemiBold)
1111 result = QCoreApplication::translate("QFontDatabase", "Demi Bold");
1112 else if (weight >= QFont::Medium)
1113 result = QCoreApplication::translate("QFontDatabase", "Medium", "The Medium font weight");
1114 } else {
1115 if (weight <= QFont::Thin)
1116 result = QCoreApplication::translate("QFontDatabase", "Thin");
1117 else if (weight <= QFont::ExtraLight)
1118 result = QCoreApplication::translate("QFontDatabase", "Extra Light");
1119 else if (weight <= QFont::Light)
1120 result = QCoreApplication::translate("QFontDatabase", "Light");
1121 }
1122
1123 if (style == QFont::StyleItalic)
1124 result += u' ' + QCoreApplication::translate("QFontDatabase", "Italic");
1125 else if (style == QFont::StyleOblique)
1126 result += u' ' + QCoreApplication::translate("QFontDatabase", "Oblique");
1127
1128 if (result.isEmpty())
1129 result = QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight");
1130
1131 return result.simplified();
1132}
1133
1144
1151{
1152 return fontInfo.styleName().isEmpty() ? styleStringHelper(fontInfo.weight(), fontInfo.style())
1153 : fontInfo.styleName();
1154}
1155
1156
1325{
1327 if (!d->populated) {
1328 // The font database may have been partially populated, but to ensure
1329 // we can answer queries for any platform- or user-provided family we
1330 // need to fully populate it now.
1331 qCDebug(lcFontDb) << "Populating font database";
1332
1333 if (Q_UNLIKELY(qGuiApp == nullptr || QGuiApplicationPrivate::platformIntegration() == nullptr))
1334 qFatal("QFontDatabase: Must construct a QGuiApplication before accessing QFontDatabase");
1335
1336 auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
1337 platformFontDatabase->populateFontDatabase();
1338
1339 for (int i = 0; i < d->applicationFonts.size(); i++) {
1340 auto *font = &d->applicationFonts[i];
1341 if (!font->isNull() && !font->isPopulated())
1342 platformFontDatabase->addApplicationFont(font->data, font->fileName, font);
1343 }
1344
1345 // Note: Both application fonts and platform fonts may be added
1346 // after this initial population, so the only thing we are tracking
1347 // is whether we've done our part in ensuring a filled font database.
1348 d->populated = true;
1349 }
1350 return d;
1351}
1352
1360QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems()
1361{
1362 QMutexLocker locker(fontDatabaseMutex());
1364
1365 quint64 writingSystemsFound = 0;
1366 static_assert(WritingSystemsCount < 64);
1367
1368 for (int i = 0; i < d->count; ++i) {
1369 QtFontFamily *family = d->families[i];
1370 if (!family->ensurePopulated())
1371 continue;
1372
1373 if (family->count == 0)
1374 continue;
1375 for (uint x = Latin; x < uint(WritingSystemsCount); ++x) {
1377 writingSystemsFound |= quint64(1) << x;
1378 }
1379 }
1380
1381 // mutex protection no longer needed - just working on local data now:
1382 locker.unlock();
1383
1384 QList<WritingSystem> list;
1385 list.reserve(qPopulationCount(writingSystemsFound));
1386 for (uint x = Latin ; x < uint(WritingSystemsCount); ++x) {
1387 if (writingSystemsFound & (quint64(1) << x))
1389 }
1390 return list;
1391}
1392
1393
1400QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family)
1401{
1402 QString familyName, foundryName;
1403 parseFontName(family, foundryName, familyName);
1404
1405 QMutexLocker locker(fontDatabaseMutex());
1407
1408 QList<WritingSystem> list;
1409 QtFontFamily *f = d->family(familyName);
1410 if (!f || f->count == 0)
1411 return list;
1412
1413 for (int x = Latin; x < WritingSystemsCount; ++x) {
1414 const WritingSystem writingSystem = WritingSystem(x);
1415 if (f->writingSystems[writingSystem] & QtFontFamily::Supported)
1416 list.append(writingSystem);
1417 }
1418 return list;
1419}
1420
1421
1433{
1434 QMutexLocker locker(fontDatabaseMutex());
1436
1437 QStringList flist;
1438 for (int i = 0; i < d->count; i++) {
1439 QtFontFamily *f = d->families[i];
1440 if (f->populated && f->count == 0)
1441 continue;
1442 if (writingSystem != Any) {
1443 if (!f->ensurePopulated())
1444 continue;
1445 if (f->writingSystems[writingSystem] != QtFontFamily::Supported)
1446 continue;
1447 }
1448 if (!f->populated || f->count == 1) {
1449 flist.append(f->name);
1450 } else {
1451 for (int j = 0; j < f->count; j++) {
1452 QString str = f->name;
1453 QString foundry = f->foundries[j]->name;
1454 if (!foundry.isEmpty()) {
1455 str += " ["_L1;
1456 str += foundry;
1457 str += u']';
1458 }
1459 flist.append(str);
1460 }
1461 }
1462 }
1463 return flist;
1464}
1465
1474{
1475 QString familyName, foundryName;
1476 parseFontName(family, foundryName, familyName);
1477
1478 QMutexLocker locker(fontDatabaseMutex());
1480
1481 QStringList l;
1482 QtFontFamily *f = d->family(familyName);
1483 if (!f)
1484 return l;
1485
1486 QtFontFoundry allStyles(foundryName);
1487 for (int j = 0; j < f->count; j++) {
1488 QtFontFoundry *foundry = f->foundries[j];
1489 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1490 for (int k = 0; k < foundry->count; k++) {
1491 QtFontStyle::Key ke(foundry->styles[k]->key);
1492 ke.stretch = 0;
1493 allStyles.style(ke, foundry->styles[k]->styleName, true);
1494 }
1495 }
1496 }
1497
1498 l.reserve(allStyles.count);
1499 for (int i = 0; i < allStyles.count; i++) {
1500 l.append(allStyles.styles[i]->styleName.isEmpty() ?
1501 styleStringHelper(allStyles.styles[i]->key.weight,
1502 (QFont::Style)allStyles.styles[i]->key.style) :
1503 allStyles.styles[i]->styleName);
1504 }
1505 return l;
1506}
1507
1514 const QString &style)
1515{
1516 Q_UNUSED(style);
1517
1518 QString familyName, foundryName;
1519 parseFontName(family, foundryName, familyName);
1520
1521 QMutexLocker locker(fontDatabaseMutex());
1523
1524 QtFontFamily *f = d->family(familyName);
1525 return (f && f->fixedPitch);
1526}
1527
1539 const QString &style)
1540{
1541 bool bitmapScalable = false;
1542 QString familyName, foundryName;
1543 parseFontName(family, foundryName, familyName);
1544
1545 QMutexLocker locker(fontDatabaseMutex());
1547
1548 QtFontFamily *f = d->family(familyName);
1549 if (!f) return bitmapScalable;
1550
1551 QtFontStyle::Key styleKey(style);
1552 for (int j = 0; j < f->count; j++) {
1553 QtFontFoundry *foundry = f->foundries[j];
1554 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1555 for (int k = 0; k < foundry->count; k++)
1556 if ((style.isEmpty() ||
1557 foundry->styles[k]->styleName == style ||
1558 foundry->styles[k]->key == styleKey)
1559 && foundry->styles[k]->bitmapScalable && !foundry->styles[k]->smoothScalable) {
1560 bitmapScalable = true;
1561 goto end;
1562 }
1563 }
1564 }
1565 end:
1566 return bitmapScalable;
1567}
1568
1569
1578bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style)
1579{
1580 bool smoothScalable = false;
1581 QString familyName, foundryName;
1582 parseFontName(family, foundryName, familyName);
1583
1584 QMutexLocker locker(fontDatabaseMutex());
1586
1587 QtFontFamily *f = d->family(familyName);
1588 if (!f) {
1589 for (int i = 0; i < d->count; i++) {
1590 if (d->families[i]->matchesFamilyName(familyName)) {
1591 f = d->families[i];
1592 if (f->ensurePopulated())
1593 break;
1594 }
1595 }
1596 }
1597 if (!f) return smoothScalable;
1598
1599 const QtFontStyle::Key styleKey(style);
1600 for (int j = 0; j < f->count; j++) {
1601 QtFontFoundry *foundry = f->foundries[j];
1602 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1603 for (int k = 0; k < foundry->count; k++) {
1604 const QtFontStyle *fontStyle = foundry->styles[k];
1607 && ((style.isEmpty()
1608 || fontStyle->styleName == style
1609 || fontStyle->key == styleKey)
1610 || (fontStyle->styleName.isEmpty()
1611 && style == styleStringHelper(fontStyle->key.weight,
1612 QFont::Style(fontStyle->key.style))));
1613 if (smoothScalable)
1614 goto end;
1615 }
1616 }
1617 }
1618 end:
1619 return smoothScalable;
1620}
1621
1629 const QString &style)
1630{
1631 QMutexLocker locker(fontDatabaseMutex());
1632 if (isSmoothlyScalable(family, style))
1633 return true;
1634 return isBitmapScalable(family, style);
1635}
1636
1637
1644QList<int> QFontDatabase::pointSizes(const QString &family,
1645 const QString &styleName)
1646{
1647 if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
1648 return standardSizes();
1649
1650 bool smoothScalable = false;
1651 QString familyName, foundryName;
1652 parseFontName(family, foundryName, familyName);
1653
1654 QMutexLocker locker(fontDatabaseMutex());
1656
1657 QList<int> sizes;
1658
1659 QtFontFamily *fam = d->family(familyName);
1660 if (!fam) return sizes;
1661
1662
1663 const int dpi = qt_defaultDpiY(); // embedded
1664
1665 QtFontStyle::Key styleKey(styleName);
1666 for (int j = 0; j < fam->count; j++) {
1667 QtFontFoundry *foundry = fam->foundries[j];
1668 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1669 QtFontStyle *style = foundry->style(styleKey, styleName);
1670 if (!style) continue;
1671
1672 if (style->smoothScalable) {
1673 smoothScalable = true;
1674 goto end;
1675 }
1676 for (int l = 0; l < style->count; l++) {
1677 const QtFontSize *size = style->pixelSizes + l;
1678
1679 if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
1680 const int pointSize = qRound(size->pixelSize * 72.0 / dpi);
1681 if (! sizes.contains(pointSize))
1682 sizes.append(pointSize);
1683 }
1684 }
1685 }
1686 }
1687 end:
1688 if (smoothScalable)
1689 return standardSizes();
1690
1691 std::sort(sizes.begin(), sizes.end());
1692 return sizes;
1693}
1694
1701QFont QFontDatabase::font(const QString &family, const QString &style,
1702 int pointSize)
1703{
1704 QString familyName, foundryName;
1705 parseFontName(family, foundryName, familyName);
1706 QMutexLocker locker(fontDatabaseMutex());
1708
1709 QtFontFoundry allStyles(foundryName);
1710 QtFontFamily *f = d->family(familyName);
1711 if (!f) return QGuiApplication::font();
1712
1713 for (int j = 0; j < f->count; j++) {
1714 QtFontFoundry *foundry = f->foundries[j];
1715 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1716 for (int k = 0; k < foundry->count; k++)
1717 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1718 }
1719 }
1720
1721 QtFontStyle::Key styleKey(style);
1722 QtFontStyle *s = bestStyle(&allStyles, styleKey, style);
1723
1724 if (!s) // no styles found?
1725 return QGuiApplication::font();
1726
1727 QFont fnt(QStringList{family}, pointSize, s->key.weight);
1728 fnt.setStyle((QFont::Style)s->key.style);
1729 if (!s->styleName.isEmpty())
1730 fnt.setStyleName(s->styleName);
1731 return fnt;
1732}
1733
1734
1743QList<int> QFontDatabase::smoothSizes(const QString &family,
1744 const QString &styleName)
1745{
1746 if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
1747 return standardSizes();
1748
1749 bool smoothScalable = false;
1750 QString familyName, foundryName;
1751 parseFontName(family, foundryName, familyName);
1752
1753 QMutexLocker locker(fontDatabaseMutex());
1755
1756 QList<int> sizes;
1757
1758 QtFontFamily *fam = d->family(familyName);
1759 if (!fam)
1760 return sizes;
1761
1762 const int dpi = qt_defaultDpiY(); // embedded
1763
1764 QtFontStyle::Key styleKey(styleName);
1765 for (int j = 0; j < fam->count; j++) {
1766 QtFontFoundry *foundry = fam->foundries[j];
1767 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1768 QtFontStyle *style = foundry->style(styleKey, styleName);
1769 if (!style) continue;
1770
1771 if (style->smoothScalable) {
1772 smoothScalable = true;
1773 goto end;
1774 }
1775 for (int l = 0; l < style->count; l++) {
1776 const QtFontSize *size = style->pixelSizes + l;
1777
1778 if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
1779 const int pointSize = qRound(size->pixelSize * 72.0 / dpi);
1780 if (! sizes.contains(pointSize))
1781 sizes.append(pointSize);
1782 }
1783 }
1784 }
1785 }
1786 end:
1787 if (smoothScalable)
1789
1790 std::sort(sizes.begin(), sizes.end());
1791 return sizes;
1792}
1793
1794
1801{
1802 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->standardSizes();
1803}
1804
1805
1812bool QFontDatabase::italic(const QString &family, const QString &style)
1813{
1814 QString familyName, foundryName;
1815 parseFontName(family, foundryName, familyName);
1816
1817 QMutexLocker locker(fontDatabaseMutex());
1819
1820 QtFontFoundry allStyles(foundryName);
1821 QtFontFamily *f = d->family(familyName);
1822 if (!f) return false;
1823
1824 for (int j = 0; j < f->count; j++) {
1825 QtFontFoundry *foundry = f->foundries[j];
1826 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1827 for (int k = 0; k < foundry->count; k++)
1828 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1829 }
1830 }
1831
1832 QtFontStyle::Key styleKey(style);
1833 QtFontStyle *s = allStyles.style(styleKey, style);
1834 return s && s->key.style == QFont::StyleItalic;
1835}
1836
1837
1844bool QFontDatabase::bold(const QString &family,
1845 const QString &style)
1846{
1847 QString familyName, foundryName;
1848 parseFontName(family, foundryName, familyName);
1849
1850 QMutexLocker locker(fontDatabaseMutex());
1852
1853 QtFontFoundry allStyles(foundryName);
1854 QtFontFamily *f = d->family(familyName);
1855 if (!f) return false;
1856
1857 for (int j = 0; j < f->count; j++) {
1858 QtFontFoundry *foundry = f->foundries[j];
1859 if (foundryName.isEmpty() ||
1860 foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1861 for (int k = 0; k < foundry->count; k++)
1862 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1863 }
1864 }
1865
1866 QtFontStyle::Key styleKey(style);
1867 QtFontStyle *s = allStyles.style(styleKey, style);
1868 return s && s->key.weight >= QFont::Bold;
1869}
1870
1871
1880 const QString &style)
1881{
1882 QString familyName, foundryName;
1883 parseFontName(family, foundryName, familyName);
1884
1885 QMutexLocker locker(fontDatabaseMutex());
1887
1888 QtFontFoundry allStyles(foundryName);
1889 QtFontFamily *f = d->family(familyName);
1890 if (!f) return -1;
1891
1892 for (int j = 0; j < f->count; j++) {
1893 QtFontFoundry *foundry = f->foundries[j];
1894 if (foundryName.isEmpty() ||
1895 foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1896 for (int k = 0; k < foundry->count; k++)
1897 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1898 }
1899 }
1900
1901 QtFontStyle::Key styleKey(style);
1902 QtFontStyle *s = allStyles.style(styleKey, style);
1903 return s ? s->key.weight : -1;
1904}
1905
1906
1909{
1910 QString parsedFamily, foundry;
1911 parseFontName(family, foundry, parsedFamily);
1912 const QString familyAlias = QFontDatabasePrivate::resolveFontFamilyAlias(parsedFamily);
1913
1914 QMutexLocker locker(fontDatabaseMutex());
1916
1917 for (int i = 0; i < d->count; i++) {
1918 QtFontFamily *f = d->families[i];
1919 if (f->populated && f->count == 0)
1920 continue;
1921 if (familyAlias.compare(f->name, Qt::CaseInsensitive) == 0)
1922 return true;
1923 }
1924
1925 return false;
1926}
1927
1928
1942{
1943 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->isPrivateFontFamily(family);
1944}
1945
1946
1952{
1953 const char *name = nullptr;
1954 switch (writingSystem) {
1955 case Any:
1956 name = QT_TRANSLATE_NOOP("QFontDatabase", "Any");
1957 break;
1958 case Latin:
1959 name = QT_TRANSLATE_NOOP("QFontDatabase", "Latin");
1960 break;
1961 case Greek:
1962 name = QT_TRANSLATE_NOOP("QFontDatabase", "Greek");
1963 break;
1964 case Cyrillic:
1965 name = QT_TRANSLATE_NOOP("QFontDatabase", "Cyrillic");
1966 break;
1967 case Armenian:
1968 name = QT_TRANSLATE_NOOP("QFontDatabase", "Armenian");
1969 break;
1970 case Hebrew:
1971 name = QT_TRANSLATE_NOOP("QFontDatabase", "Hebrew");
1972 break;
1973 case Arabic:
1974 name = QT_TRANSLATE_NOOP("QFontDatabase", "Arabic");
1975 break;
1976 case Syriac:
1977 name = QT_TRANSLATE_NOOP("QFontDatabase", "Syriac");
1978 break;
1979 case Thaana:
1980 name = QT_TRANSLATE_NOOP("QFontDatabase", "Thaana");
1981 break;
1982 case Devanagari:
1983 name = QT_TRANSLATE_NOOP("QFontDatabase", "Devanagari");
1984 break;
1985 case Bengali:
1986 name = QT_TRANSLATE_NOOP("QFontDatabase", "Bengali");
1987 break;
1988 case Gurmukhi:
1989 name = QT_TRANSLATE_NOOP("QFontDatabase", "Gurmukhi");
1990 break;
1991 case Gujarati:
1992 name = QT_TRANSLATE_NOOP("QFontDatabase", "Gujarati");
1993 break;
1994 case Oriya:
1995 name = QT_TRANSLATE_NOOP("QFontDatabase", "Oriya");
1996 break;
1997 case Tamil:
1998 name = QT_TRANSLATE_NOOP("QFontDatabase", "Tamil");
1999 break;
2000 case Telugu:
2001 name = QT_TRANSLATE_NOOP("QFontDatabase", "Telugu");
2002 break;
2003 case Kannada:
2004 name = QT_TRANSLATE_NOOP("QFontDatabase", "Kannada");
2005 break;
2006 case Malayalam:
2007 name = QT_TRANSLATE_NOOP("QFontDatabase", "Malayalam");
2008 break;
2009 case Sinhala:
2010 name = QT_TRANSLATE_NOOP("QFontDatabase", "Sinhala");
2011 break;
2012 case Thai:
2013 name = QT_TRANSLATE_NOOP("QFontDatabase", "Thai");
2014 break;
2015 case Lao:
2016 name = QT_TRANSLATE_NOOP("QFontDatabase", "Lao");
2017 break;
2018 case Tibetan:
2019 name = QT_TRANSLATE_NOOP("QFontDatabase", "Tibetan");
2020 break;
2021 case Myanmar:
2022 name = QT_TRANSLATE_NOOP("QFontDatabase", "Myanmar");
2023 break;
2024 case Georgian:
2025 name = QT_TRANSLATE_NOOP("QFontDatabase", "Georgian");
2026 break;
2027 case Khmer:
2028 name = QT_TRANSLATE_NOOP("QFontDatabase", "Khmer");
2029 break;
2030 case SimplifiedChinese:
2031 name = QT_TRANSLATE_NOOP("QFontDatabase", "Simplified Chinese");
2032 break;
2033 case TraditionalChinese:
2034 name = QT_TRANSLATE_NOOP("QFontDatabase", "Traditional Chinese");
2035 break;
2036 case Japanese:
2037 name = QT_TRANSLATE_NOOP("QFontDatabase", "Japanese");
2038 break;
2039 case Korean:
2040 name = QT_TRANSLATE_NOOP("QFontDatabase", "Korean");
2041 break;
2042 case Vietnamese:
2043 name = QT_TRANSLATE_NOOP("QFontDatabase", "Vietnamese");
2044 break;
2045 case Symbol:
2046 name = QT_TRANSLATE_NOOP("QFontDatabase", "Symbol");
2047 break;
2048 case Ogham:
2049 name = QT_TRANSLATE_NOOP("QFontDatabase", "Ogham");
2050 break;
2051 case Runic:
2052 name = QT_TRANSLATE_NOOP("QFontDatabase", "Runic");
2053 break;
2054 case Nko:
2055 name = QT_TRANSLATE_NOOP("QFontDatabase", "N'Ko");
2056 break;
2057 default:
2058 Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter");
2059 break;
2060 }
2061 return QCoreApplication::translate("QFontDatabase", name);
2062}
2063
2068{
2069 return [&]() -> QStringView {
2070 switch (writingSystem) {
2071 case QFontDatabase::Any:
2073 // show only ascii characters
2074 return u"AaBbzZ";
2076 // This is cheating... we only show latin-1 characters so that we don't
2077 // end up loading lots of fonts - at least on X11...
2078 return u"Aa\x00C3\x00E1Zz";
2080 return u"\x0393\x03B1\x03A9\x03C9";
2082 return u"\x0414\x0434\x0436\x044f";
2084 return u"\x053f\x054f\x056f\x057f";
2086 return u"\x05D0\x05D1\x05D2\x05D3";
2088 return u"\x0623\x0628\x062C\x062F\x064A\x0629\x0020\x0639\x0631\x0628\x064A\x0629";
2090 return u"\x0715\x0725\x0716\x0726";
2092 return u"\x0784\x0794\x078c\x078d";
2094 return u"\x0905\x0915\x0925\x0935";
2096 return u"\x0986\x0996\x09a6\x09b6";
2098 return u"\x0a05\x0a15\x0a25\x0a35";
2100 return u"\x0a85\x0a95\x0aa5\x0ab5";
2102 return u"\x0b06\x0b16\x0b2b\x0b36";
2104 return u"\x0b89\x0b99\x0ba9\x0bb9";
2106 return u"\x0c05\x0c15\x0c25\x0c35";
2108 return u"\x0c85\x0c95\x0ca5\x0cb5";
2110 return u"\x0d05\x0d15\x0d25\x0d35";
2112 return u"\x0d90\x0da0\x0db0\x0dc0";
2114 return u"\x0e02\x0e12\x0e22\x0e32";
2115 case QFontDatabase::Lao:
2116 return u"\x0e8d\x0e9d\x0ead\x0ebd";
2118 return u"\x0f00\x0f01\x0f02\x0f03";
2120 return u"\x1000\x1001\x1002\x1003";
2122 return u"\x10a0\x10b0\x10c0\x10d0";
2124 return u"\x1780\x1790\x17b0\x17c0";
2126 return u"\x4e2d\x6587\x8303\x4f8b";
2128 return u"\x4e2d\x6587\x7bc4\x4f8b";
2130 return u"\x30b5\x30f3\x30d7\x30eb\x3067\x3059";
2132 return u"\xac00\xac11\xac1a\xac2f";
2134 return u"\x1ED7\x1ED9\x1ED1\x1ED3";
2136 return u"\x1681\x1682\x1683\x1684";
2138 return u"\x16a0\x16a1\x16a2\x16a3";
2139 case QFontDatabase::Nko:
2140 return u"\x7ca\x7cb\x7cc\x7cd";
2141 default:
2142 return nullptr;
2143 }
2144 }().toString();
2145}
2146
2148{
2149 QT_PREPEND_NAMESPACE(parseFontName)(name, foundry, family);
2150}
2151
2152// used from qfontengine_ft.cpp
2154{
2155 QMutexLocker locker(fontDatabaseMutex());
2156 return QFontDatabasePrivate::instance()->applicationFonts.value(index).data;
2157}
2158
2160{
2162 font.data = fontData;
2163 font.fileName = fileName;
2164
2165 Q_TRACE(QFontDatabasePrivate_addAppFont, fileName);
2166
2167 int i;
2168 for (i = 0; i < applicationFonts.size(); ++i)
2169 if (applicationFonts.at(i).isNull())
2170 break;
2171 if (i >= applicationFonts.size()) {
2172 applicationFonts.append(ApplicationFont());
2173 i = applicationFonts.size() - 1;
2174 }
2175
2176 if (font.fileName.isEmpty() && !fontData.isEmpty())
2177 font.fileName = ":qmemoryfonts/"_L1 + QString::number(i);
2178
2179 auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
2180 platformFontDatabase->addApplicationFont(font.data, font.fileName, &font);
2181 if (font.properties.isEmpty())
2182 return -1;
2183
2184 applicationFonts[i] = font;
2185
2186 // The font cache may have cached lookups for the font that was now
2187 // loaded, so it has to be flushed.
2188 QFontCache::instance()->clear();
2189
2190 emit qApp->fontDatabaseChanged();
2191
2192 return i;
2193}
2194
2196{
2197 for (int i = 0; i < applicationFonts.size(); ++i)
2198 if (applicationFonts.at(i).fileName == fileName)
2199 return true;
2200 return false;
2201}
2202
2212
2217
2221{
2223 if (!QFileInfo(fileName).isNativePath()) {
2224 QFile f(fileName);
2225 if (!f.open(QIODevice::ReadOnly))
2226 return -1;
2227
2228 Q_TRACE(QFontDatabase_addApplicationFont, fileName);
2229
2230 data = f.readAll();
2231 }
2232 QMutexLocker locker(fontDatabaseMutex());
2233 return QFontDatabasePrivate::instance()->addAppFont(data, fileName);
2234}
2235
2249{
2250 QMutexLocker locker(fontDatabaseMutex());
2251 return QFontDatabasePrivate::instance()->addAppFont(fontData, QString() /* fileName */);
2252}
2253
2263{
2264 QMutexLocker locker(fontDatabaseMutex());
2266
2268 ret.reserve(d->applicationFonts.value(id).properties.size());
2269
2270 for (const auto &properties : d->applicationFonts.value(id).properties)
2271 ret.append(properties.familyName);
2272
2273 return ret;
2274}
2275
2286{
2287 const QFont *font = nullptr;
2289 switch (type) {
2290 case GeneralFont:
2291 font = theme->font(QPlatformTheme::SystemFont);
2292 break;
2293 case FixedFont:
2294 font = theme->font(QPlatformTheme::FixedFont);
2295 break;
2296 case TitleFont:
2297 font = theme->font(QPlatformTheme::TitleBarFont);
2298 break;
2299 case SmallestReadableFont:
2300 font = theme->font(QPlatformTheme::MiniFont);
2301 break;
2302 }
2303 }
2304
2305 if (font)
2306 return *font;
2308 return integration->fontDatabase()->defaultFont();
2309 else
2310 return QFont();
2311}
2312
2325{
2326 QMutexLocker locker(fontDatabaseMutex());
2327
2329 if (handle < 0 || handle >= db->applicationFonts.size())
2330 return false;
2331
2332 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
2333
2334 db->invalidate();
2335 return true;
2336}
2337
2351{
2352 QMutexLocker locker(fontDatabaseMutex());
2353
2355 if (!db || db->applicationFonts.isEmpty())
2356 return false;
2357
2358 db->applicationFonts.clear();
2359 db->invalidate();
2360 return true;
2361}
2362
2391void QFontDatabase::addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
2392{
2393 QMutexLocker locker(fontDatabaseMutex());
2394
2395 if (script < QChar::Script_Latin) {
2396 qCWarning(lcFontDb) << "Invalid script passed to addApplicationFallbackFontFamily:" << script;
2397 return;
2398 }
2399
2401 auto it = db->applicationFallbackFontFamilies.find(script);
2402 if (it == db->applicationFallbackFontFamilies.end())
2403 it = db->applicationFallbackFontFamilies.insert(script, QStringList{});
2404
2405 it->prepend(familyName);
2406 db->fallbacksCache.clear();
2407}
2408
2419bool QFontDatabase::removeApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
2420{
2421 QMutexLocker locker(fontDatabaseMutex());
2422
2424 auto it = db->applicationFallbackFontFamilies.find(script);
2425 if (it != db->applicationFallbackFontFamilies.end()) {
2426 if (it->removeAll(familyName) > 0) {
2427 if (it->isEmpty())
2428 it = db->applicationFallbackFontFamilies.erase(it);
2429 QFontCache::instance()->clear();
2430 db->fallbacksCache.clear();
2431 return true;
2432 }
2433 }
2434
2435 return false;
2436}
2437
2451void QFontDatabase::setApplicationFallbackFontFamilies(QChar::Script script, const QStringList &familyNames)
2452{
2453 QMutexLocker locker(fontDatabaseMutex());
2454
2455 if (script < QChar::Script_Latin) {
2456 qCWarning(lcFontDb) << "Invalid script passed to setApplicationFallbackFontFamilies:" << script;
2457 return;
2458 }
2459
2461 db->applicationFallbackFontFamilies[script] = familyNames;
2462
2463 QFontCache::instance()->clear();
2464 db->fallbacksCache.clear();
2465}
2466
2476{
2477 QMutexLocker locker(fontDatabaseMutex());
2478
2480 return db->applicationFallbackFontFamilies.value(script);
2481}
2482
2487 int script,
2488 bool preferScriptOverFamily)
2489{
2490 QMutexLocker locker(fontDatabaseMutex());
2491 ensureFontDatabase();
2492
2494
2495#ifdef Q_OS_WIN
2496 const QFontDef request = static_cast<QWindowsFontDatabaseBase *>(
2498 ->sanitizeRequest(req);
2499#else
2500 const QFontDef &request = req;
2501#endif
2502
2503#if defined(QT_BUILD_INTERNAL)
2504 // For testing purpose only, emulates an exact-matching monospace font
2505 if (qt_enable_test_font && request.families.first() == "__Qt__Box__Engine__"_L1) {
2506 engine = new QTestFontEngine(request.pixelSize);
2507 engine->fontDef = request;
2508 return engine;
2509 }
2510#endif
2511
2512 QFontCache *fontCache = QFontCache::instance();
2513
2514 // Until we specifically asked not to, try looking for Multi font engine
2515 // first, the last '1' indicates that we want Multi font engine instead
2516 // of single ones
2517 bool multi = !(request.styleStrategy & QFont::NoFontMerging);
2518 QFontCache::Key key(request, script, multi ? 1 : 0);
2519 engine = fontCache->findEngine(key);
2520 if (engine) {
2521 qCDebug(lcFontMatch, "Cache hit level 1");
2522 return engine;
2523 }
2524
2525 if (request.pixelSize > 0xffff) {
2526 // Stop absurd requests reaching the engines; pixel size is assumed to fit ushort
2527 qCDebug(lcFontMatch, "Rejecting request for pixel size %g2, returning box engine", double(request.pixelSize));
2528 return new QFontEngineBox(32); // not request.pixelSize, to avoid overflow/DOS
2529 }
2530
2531 QString family_name, foundry_name;
2532 const QString requestFamily = request.families.at(0);
2533 parseFontName(requestFamily, foundry_name, family_name);
2534 QtFontDesc desc;
2535 QList<int> blackListed;
2536 unsigned int score = UINT_MAX;
2537 int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed, &score);
2538 if (score > 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
2539 // We populated family aliases (e.g. localized families), so try again
2540 index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
2541 }
2542
2543 // If we do not find a match and NoFontMerging is set, use the requested font even if it does
2544 // not support the script.
2545 //
2546 // (we do this at the end to prefer foundries that support the script if they exist)
2547 if (index < 0 && !multi && !preferScriptOverFamily)
2548 index = match(QChar::Script_Common, request, family_name, foundry_name, &desc, blackListed);
2549
2550 if (index >= 0) {
2551 QFontDef fontDef = request;
2552 // Don't pass empty family names to the platform font database, since it will then invoke its own matching
2553 // and we will be out of sync with the matched font.
2554 if (fontDef.families.isEmpty())
2555 fontDef.families = QStringList(desc.family->name);
2556
2557 engine = loadEngine(script, fontDef, desc.family, desc.foundry, desc.style, desc.size);
2558
2559 if (engine)
2560 initFontDef(desc, request, &engine->fontDef, multi);
2561 else
2562 blackListed.append(index);
2563 } else {
2564 qCDebug(lcFontMatch, " NO MATCH FOUND\n");
2565 }
2566
2567 if (!engine) {
2568 if (!requestFamily.isEmpty()) {
2569 QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
2570 if (styleHint == QFont::AnyStyle && request.fixedPitch)
2571 styleHint = QFont::TypeWriter;
2572
2573 QStringList fallbacks = request.fallBackFamilies
2574 + fallbacksForFamily(requestFamily,
2575 QFont::Style(request.style),
2576 styleHint,
2577 QChar::Script(script));
2578 if (script > QChar::Script_Common)
2579 fallbacks += QString(); // Find the first font matching the specified script.
2580
2581 for (int i = 0; !engine && i < fallbacks.size(); i++) {
2582 QFontDef def = request;
2583 def.families = QStringList(fallbacks.at(i));
2584 QFontCache::Key key(def, script, multi ? 1 : 0);
2585 engine = fontCache->findEngine(key);
2586 if (!engine) {
2587 QtFontDesc desc;
2588 do {
2589 index = match(multi ? QChar::Script_Common : script, def, def.families.constFirst(), ""_L1, &desc, blackListed);
2590 if (index >= 0) {
2591 QFontDef loadDef = def;
2592 if (loadDef.families.isEmpty())
2593 loadDef.families = QStringList(desc.family->name);
2594 engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size);
2595 if (engine)
2596 initFontDef(desc, loadDef, &engine->fontDef, multi);
2597 else
2598 blackListed.append(index);
2599 }
2600 } while (index >= 0 && !engine);
2601 }
2602 }
2603 }
2604
2605 if (!engine)
2606 engine = new QFontEngineBox(request.pixelSize);
2607
2608 qCDebug(lcFontMatch, "returning box engine");
2609 }
2610
2611 return engine;
2612}
2613
2615{
2616 QFontDef req = d->request;
2617
2618 if (req.pixelSize == -1) {
2619 req.pixelSize = std::floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100;
2620 req.pixelSize = qRound(req.pixelSize);
2621 }
2622 if (req.pointSize < 0)
2623 req.pointSize = req.pixelSize*72.0/d->dpi;
2624
2625 // respect the fallback families that might be passed through the request
2626 const QStringList fallBackFamilies = familyList(req);
2627
2628 if (!d->engineData) {
2629 QFontCache *fontCache = QFontCache::instance();
2630 // look for the requested font in the engine data cache
2631 // note: fallBackFamilies are not respected in the EngineData cache key;
2632 // join them with the primary selection family to avoid cache misses
2633 if (!d->request.families.isEmpty())
2634 req.families = fallBackFamilies;
2635
2636 d->engineData = fontCache->findEngineData(req);
2637 if (!d->engineData) {
2638 // create a new one
2639 d->engineData = new QFontEngineData;
2640 fontCache->insertEngineData(req, d->engineData);
2641 }
2642 d->engineData->ref.ref();
2643 }
2644
2645 // the cached engineData could have already loaded the engine we want
2646 if (d->engineData->engines[script])
2647 return;
2648
2649 QFontEngine *fe = nullptr;
2650
2651 Q_TRACE(QFontDatabase_load, req.families.join(QLatin1Char(';')), req.pointSize);
2652
2653 req.fallBackFamilies = fallBackFamilies;
2654 if (!req.fallBackFamilies.isEmpty())
2655 req.families = QStringList(req.fallBackFamilies.takeFirst());
2656
2657 // list of families to try
2658 QStringList family_list;
2659
2660 if (!req.families.isEmpty()) {
2661 // Add primary selection
2662 family_list << req.families.at(0);
2663
2664 // add the default family
2665 const auto families = QGuiApplication::font().families();
2666 if (!families.isEmpty()) {
2667 QString defaultFamily = families.first();
2668 if (! family_list.contains(defaultFamily))
2669 family_list << defaultFamily;
2670 }
2671
2672 }
2673
2674 // null family means find the first font matching the specified script
2675 family_list << QString();
2676
2677 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
2678 for (; !fe && it != end; ++it) {
2679 req.families = QStringList(*it);
2680
2681 fe = QFontDatabasePrivate::findFont(req, script);
2682 if (fe) {
2683 if (fe->type() == QFontEngine::Box && !req.families.at(0).isEmpty()) {
2684 if (fe->ref.loadRelaxed() == 0)
2685 delete fe;
2686 fe = nullptr;
2687 } else {
2688 if (d->dpi > 0)
2689 fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / d->dpi));
2690 }
2691 }
2692
2693 // No need to check requested fallback families again
2694 req.fallBackFamilies.clear();
2695 }
2696
2697 Q_ASSERT(fe);
2698 if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
2699 for (int i = 0; i < QChar::ScriptCount; ++i) {
2700 if (!d->engineData->engines[i]) {
2701 d->engineData->engines[i] = fe;
2702 fe->ref.ref();
2703 }
2704 }
2705 } else {
2706 d->engineData->engines[script] = fe;
2707 fe->ref.ref();
2708 }
2709}
2710
2712{
2713 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
2714}
2715
2716Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script, const QStringList &families)
2717{
2718 size_t writingSystem = qt_writing_system_for_script(script);
2719 if (writingSystem == QFontDatabase::Any
2720 || writingSystem >= QFontDatabase::WritingSystemsCount) {
2721 return families;
2722 }
2723
2725 QMultiMap<uint, QString> supported;
2726 for (int i = 0; i < families.size(); ++i) {
2727 const QString &family = families.at(i);
2728
2729 QtFontFamily *testFamily = nullptr;
2730 for (int x = 0; x < db->count; ++x) {
2731 if (Q_UNLIKELY(matchFamilyName(family, db->families[x]))) {
2732 testFamily = db->families[x];
2733 if (testFamily->ensurePopulated())
2734 break;
2735 }
2736 }
2737
2738 uint order = i;
2739 if (testFamily == nullptr
2740 || !familySupportsWritingSystem(testFamily, writingSystem)) {
2741 order |= 1u << 31;
2742 }
2743
2744 supported.insert(order, family);
2745 }
2746
2747 return supported.values();
2748}
2749
2751
2752#include "moc_qfontdatabase.cpp"
2753
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
\inmodule QtCore
Definition qfile.h:93
void insertEngineData(const QFontDef &def, QFontEngineData *engineData)
Definition qfont.cpp:3443
QFontEngine * findEngine(const Key &key)
Definition qfont.cpp:3464
QFontEngineData * findEngineData(const QFontDef &def) const
Definition qfont.cpp:3433
static QFontCache * instance()
Definition qfont.cpp:3336
void insertEngine(const Key &key, QFontEngine *engine, bool insertMulti=false)
Definition qfont.cpp:3491
bool isApplicationFont(const QString &fileName)
static void parseFontName(const QString &name, QString &foundry, QString &family)
static void load(const QFontPrivate *d, int script)
static QFontDatabasePrivate * ensureFontDatabase()
static QFontDatabasePrivate * instance()
static QFontEngine * findFont(const QFontDef &request, int script, bool preferScriptOverFamily=false)
static QString resolveFontFamilyAlias(const QString &family)
QtFontFamily * family(const QString &f, FamilyRequestFlags flags=EnsurePopulated)
int addAppFont(const QByteArray &fontData, const QString &fileName)
static QList< int > standardSizes()
Returns a list of standard font sizes.
SystemFont
\value GeneralFont The default system font.
static int addApplicationFontFromData(const QByteArray &fontData)
static QString writingSystemName(WritingSystem writingSystem)
Returns the names the writingSystem (e.g.
static bool bold(const QString &family, const QString &style)
Returns true if the font that has family family and style style is bold; otherwise returns false.
WritingSystem
\value Any \value Latin \value Greek \value Cyrillic \value Armenian \value Hebrew \value Arabic \val...
static bool isSmoothlyScalable(const QString &family, const QString &style=QString())
Returns true if the font that has family family and style style is smoothly scalable; otherwise retur...
static int addApplicationFont(const QString &fileName)
static bool isPrivateFamily(const QString &family)
static QString styleString(const QFont &font)
Returns a string that describes the style of the font.
static bool italic(const QString &family, const QString &style)
Returns true if the font that has family family and style style is italic; otherwise returns false.
static void addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
static QFont font(const QString &family, const QString &style, int pointSize)
Returns a QFont object that has family family, style style and point size pointSize.
static QString writingSystemSample(WritingSystem writingSystem)
Returns a string with sample characters from writingSystem.
static bool removeApplicationFont(int id)
static QStringList applicationFallbackFontFamilies(QChar::Script script)
static bool isScalable(const QString &family, const QString &style=QString())
Returns true if the font that has family family and style style is scalable; otherwise returns false.
static void setApplicationFallbackFontFamilies(QChar::Script, const QStringList &familyNames)
static QStringList families(WritingSystem writingSystem=Any)
Returns a sorted list of the available font families which support the writingSystem.
static bool removeApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
static bool isBitmapScalable(const QString &family, const QString &style=QString())
Returns true if the font that has family family and style style is a scalable bitmap font; otherwise ...
static bool hasFamily(const QString &family)
static QList< int > smoothSizes(const QString &family, const QString &style)
Returns the point sizes of a font that has family family and style styleName that will look attractiv...
static QList< WritingSystem > writingSystems()
Returns a sorted list of the available writing systems.
static QList< int > pointSizes(const QString &family, const QString &style=QString())
Returns a list of the point sizes available for the font that has family family and style styleName.
static QFont systemFont(SystemFont type)
static QStringList applicationFontFamilies(int id)
static QStringList styles(const QString &family)
Returns a list of the styles available for the font family family.
static bool removeAllApplicationFonts()
static bool isFixedPitch(const QString &family, const QString &style=QString())
Returns true if the font that has family family and style style is fixed pitch; otherwise returns fal...
static int weight(const QString &family, const QString &style)
Returns the weight of the font that has family family and style style.
\reentrant
Definition qfontinfo.h:16
QString styleName() const
Definition qfont.cpp:3107
QFont::Style style() const
Returns the style value of the matched window system font.
Definition qfont.cpp:3167
int weight() const
Returns the weight of the matched window system font.
Definition qfont.cpp:3201
\reentrant
Definition qfont.h:22
static QStringList substitutes(const QString &)
Returns a list of family names to be used whenever familyName is specified.
Definition qfont.cpp:1958
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
Definition qfont.h:25
@ AnyStyle
Definition qfont.h:31
@ TypeWriter
Definition qfont.h:28
void setStyle(Style style)
Sets the style of the font to style.
Definition qfont.cpp:1116
QString styleName() const
Definition qfont.cpp:849
Weight weight() const
Returns the weight of the font, using the same scale as the \l{QFont::Weight} enumeration.
Definition qfont.cpp:1133
@ AnyStretch
Definition qfont.h:84
Style style() const
Returns the style of the font.
Definition qfont.cpp:1105
@ PreferQuality
Definition qfont.h:45
@ PreferBitmap
Definition qfont.h:40
@ ForceOutline
Definition qfont.h:43
@ PreferMatch
Definition qfont.h:44
@ NoFontMerging
Definition qfont.h:51
@ DemiBold
Definition qfont.h:69
@ Thin
Definition qfont.h:64
@ ExtraBold
Definition qfont.h:71
@ Black
Definition qfont.h:72
@ Bold
Definition qfont.h:70
@ ExtraLight
Definition qfont.h:65
@ Normal
Definition qfont.h:67
@ Light
Definition qfont.h:66
@ Medium
Definition qfont.h:68
Style
This enum describes the different styles of glyphs that are used to display text.
Definition qfont.h:76
@ StyleItalic
Definition qfont.h:78
@ StyleNormal
Definition qfont.h:77
@ StyleOblique
Definition qfont.h:79
static QPlatformIntegration * platformIntegration()
static QPlatformTheme * platformTheme()
static QFont font()
Returns the default application font.
void push_back(parameter_type t)
Definition qlist.h:675
void reserve(qsizetype size)
Definition qlist.h:753
void append(parameter_type t)
Definition qlist.h:458
const_iterator ConstIterator
Definition qlist.h:250
\inmodule QtCore
Definition qmutex.h:313
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:319
The QPlatformFontDatabase class makes it possible to customize how fonts are discovered and how they ...
virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
virtual QPlatformFontDatabase * fontDatabase() const
Accessor for the platform integration's fontdatabase.
The QPlatformTheme class allows customizing the UI based on themes.
\inmodule QtCore
Definition qmutex.h:309
bool isEmpty() const
Definition qset.h:52
const_iterator constBegin() const noexcept
Definition qset.h:139
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
QByteArray toLatin1() const &
Definition qstring.h:630
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString first(qsizetype n) const &
Definition qstring.h:390
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6664
QString toLower() const &
Definition qstring.h:435
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QString & append(QChar c)
Definition qstring.cpp:3252
The QSupportedWritingSystems class is used when registering fonts with the internal Qt fontdatabase.
bool supported(QFontDatabase::WritingSystem) const
Returns true if the writing system specified by writingSystem is supported; otherwise returns false.
QString str
[2]
QString text
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ CaseInsensitive
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
#define qApp
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]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
QRecursiveMutex * qt_fontdatabase_mutex()
QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:125
static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSystem)
static bool equalsCaseInsensitive(const QString &a, const QString &b)
static void parseFontName(const QString &name, QString &foundry, QString &family)
bool qt_isFontFamilyPopulated(const QString &familyName)
void qt_registerFont(const QString &familyName, const QString &stylename, const QString &foundryname, int weight, QFont::Style style, int stretch, bool antialiased, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *handle)
#define SMOOTH_SCALABLE
static QString styleStringHelper(int weight, QFont::Style style)
static const int scriptForWritingSystem[]
Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script, const QStringList &families)
static int getFontWeight(const QString &weightString)
static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script)
static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi)
static QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
Q_GUI_EXPORT int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem)
void qt_registerFontFamily(const QString &familyName)
void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
QString qt_resolveFontFamilyAlias(const QString &alias)
static QStringList familyList(const QFontDef &req)
static QtFontStyle * bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey, const QString &styleName=QString())
QByteArray qt_fontdata_from_index(int)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
void qt_cleanupFontDatabase()
#define qGuiApp
static QByteArray cacheKey(Args &&...args)
#define qWarning
Definition qlogging.h:166
#define qFatal
Definition qlogging.h:168
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLboolean GLboolean GLboolean b
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLuint GLuint GLfloat weight
GLsizei GLsizei GLfloat distance
GLenum type
GLbitfield flags
GLenum const void GLbitfield fontStyle
GLuint name
GLenum GLsizeiptr const void * fontData
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLuint64EXT * result
[6]
GLenum GLsizei len
GLfixed GLfixed GLint GLint order
static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
static QStringList aliases(const QQmlJSScope::ConstPtr &scope)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define qPrintable(string)
Definition qstring.h:1531
#define s2
#define Q_AUTOTEST_EXPORT
#define emit
#define Q_UNUSED(x)
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
#define QT_TRANSLATE_NOOP(scope, x)
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
QList< int > list
[14]
Q_CHECK_PTR(a=new int[80])
std::uniform_real_distribution dist(1, 2.5)
[2]
QObject::connect nullptr
QMimeDatabase db
[0]
QNetworkRequest request(url)
view create()
char * toString(const MyType &t)
[31]
QJSEngine engine
[0]
uint stretch
Definition qfont_p.h:65
uint style
Definition qfont_p.h:66
uint styleStrategy
Definition qfont_p.h:64
QStringList fallBackFamilies
Definition qfont_p.h:57
uint fixedPitch
Definition qfont_p.h:71
qreal pixelSize
Definition qfont_p.h:61
uint ignorePitch
Definition qfont_p.h:72
uint weight
Definition qfont_p.h:70
QStringList families
Definition qfont_p.h:54
uint styleHint
Definition qfont_p.h:69
qreal pointSize
Definition qfont_p.h:60
\inmodule QtCore \reentrant
Definition qchar.h:18
QtFontFoundry * foundry
QtFontFamily * family
QtFontStyle * style
QtFontSize * size
QtFontFoundry ** foundries
unsigned char writingSystems[QFontDatabase::WritingSystemsCount]
QStringList aliases
bool matchesFamilyName(const QString &familyName) const
QtFontFoundry * foundry(const QString &f, bool=false)
QtFontStyle * style(const QtFontStyle::Key &, const QString &=QString(), bool=false)
QtFontStyle ** styles
unsigned short pixelSize
QtFontSize * pixelSizes
QtFontStyle(const Key &k)
QtFontSize * pixelSize(unsigned short size, bool=false)
signed int count