1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qfontdatabase.h"
41 #include "qloggingcategory.h"
42 #include "qalgorithms.h"
43 #include "qguiapplication.h"
44 #include "qvarlengtharray.h" // here or earlier - workaround for VC++6
45 #include "qthread.h"
46 #include "qmutex.h"
47 #include "qfile.h"
48 #include "qfileinfo.h"
49 #include "qfontengine_p.h"
50 #include <qpa/qplatformintegration.h>
51
52 #include <QtGui/private/qguiapplication_p.h>
53 #include <qpa/qplatformfontdatabase.h>
54 #include <qpa/qplatformtheme.h>
55
56 #include <QtCore/qcache.h>
57 #include <QtCore/qmath.h>
58
59 #include <stdlib.h>
60 #include <algorithm>
61
62 #include <qtgui_tracepoints_p.h>
63
64 QT_BEGIN_NAMESPACE
65
66 Q_LOGGING_CATEGORY(lcFontDb, "qt.text.font.db")
67 Q_LOGGING_CATEGORY(lcFontMatch, "qt.text.font.match")
68
69 #define SMOOTH_SCALABLE 0xffff
70
71 #if defined(QT_BUILD_INTERNAL)
72 bool qt_enable_test_font = false;
73
qt_setQtEnableTestFont(bool value)74 Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value)
75 {
76 qt_enable_test_font = value;
77 }
78 #endif
79
getFontWeight(const QString & weightString)80 static int getFontWeight(const QString &weightString)
81 {
82 QString s = weightString.toLower();
83
84 // Order here is important. We want to match the common cases first, but we
85 // must also take care to acknowledge the cost of our tests.
86 //
87 // As a result, we test in two orders; the order of commonness, and the
88 // order of "expense".
89 //
90 // A simple string test is the cheapest, so let's do that first.
91 // Test in decreasing order of commonness
92 if (s == QLatin1String("normal") || s == QLatin1String("regular"))
93 return QFont::Normal;
94 if (s == QLatin1String("bold"))
95 return QFont::Bold;
96 if (s == QLatin1String("semibold") || s == QLatin1String("semi bold")
97 || s == QLatin1String("demibold") || s == QLatin1String("demi bold"))
98 return QFont::DemiBold;
99 if (s == QLatin1String("medium"))
100 return QFont::Medium;
101 if (s == QLatin1String("black"))
102 return QFont::Black;
103 if (s == QLatin1String("light"))
104 return QFont::Light;
105 if (s == QLatin1String("thin"))
106 return QFont::Thin;
107 const QStringRef s2 = s.midRef(2);
108 if (s.startsWith(QLatin1String("ex")) || s.startsWith(QLatin1String("ul"))) {
109 if (s2 == QLatin1String("tralight") || s == QLatin1String("tra light"))
110 return QFont::ExtraLight;
111 if (s2 == QLatin1String("trabold") || s2 == QLatin1String("tra bold"))
112 return QFont::ExtraBold;
113 }
114
115 // Next up, let's see if contains() matches: slightly more expensive, but
116 // still fast enough.
117 if (s.contains(QLatin1String("bold"))) {
118 if (s.contains(QLatin1String("demi")))
119 return QFont::DemiBold;
120 return QFont::Bold;
121 }
122 if (s.contains(QLatin1String("thin")))
123 return QFont::Thin;
124 if (s.contains(QLatin1String("light")))
125 return QFont::Light;
126 if (s.contains(QLatin1String("black")))
127 return QFont::Black;
128
129 // Now, we perform string translations & comparisons with those.
130 // These are (very) slow compared to simple string ops, so we do these last.
131 // As using translated values for such things is not very common, this should
132 // not be too bad.
133 if (s.compare(QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight"), Qt::CaseInsensitive) == 0)
134 return QFont::Normal;
135 const QString translatedBold = QCoreApplication::translate("QFontDatabase", "Bold").toLower();
136 if (s == translatedBold)
137 return QFont::Bold;
138 if (s.compare(QCoreApplication::translate("QFontDatabase", "Demi Bold"), Qt::CaseInsensitive) == 0)
139 return QFont::DemiBold;
140 if (s.compare(QCoreApplication::translate("QFontDatabase", "Medium", "The Medium font weight"), Qt::CaseInsensitive) == 0)
141 return QFont::Medium;
142 if (s.compare(QCoreApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0)
143 return QFont::Black;
144 const QString translatedLight = QCoreApplication::translate("QFontDatabase", "Light").toLower();
145 if (s == translatedLight)
146 return QFont::Light;
147 if (s.compare(QCoreApplication::translate("QFontDatabase", "Thin"), Qt::CaseInsensitive) == 0)
148 return QFont::Thin;
149 if (s.compare(QCoreApplication::translate("QFontDatabase", "Extra Light"), Qt::CaseInsensitive) == 0)
150 return QFont::ExtraLight;
151 if (s.compare(QCoreApplication::translate("QFontDatabase", "Extra Bold"), Qt::CaseInsensitive) == 0)
152 return QFont::ExtraBold;
153
154 // And now the contains() checks for the translated strings.
155 //: The word for "Extra" as in "Extra Bold, Extra Thin" used as a pattern for string searches
156 const QString translatedExtra = QCoreApplication::translate("QFontDatabase", "Extra").toLower();
157 if (s.contains(translatedBold)) {
158 //: The word for "Demi" as in "Demi Bold" used as a pattern for string searches
159 QString translatedDemi = QCoreApplication::translate("QFontDatabase", "Demi").toLower();
160 if (s .contains(translatedDemi))
161 return QFont::DemiBold;
162 if (s.contains(translatedExtra))
163 return QFont::ExtraBold;
164 return QFont::Bold;
165 }
166
167 if (s.contains(translatedLight)) {
168 if (s.contains(translatedExtra))
169 return QFont::ExtraLight;
170 return QFont::Light;
171 }
172 return QFont::Normal;
173 }
174
175
176 struct QtFontSize
177 {
178
179 void *handle;
180
181 unsigned short pixelSize : 16;
182 };
183
184
185
186 struct QtFontStyle
187 {
188 struct Key {
189 Key(const QString &styleString);
KeyQtFontStyle::Key190 Key() : style(QFont::StyleNormal),
191 weight(QFont::Normal), stretch(0) { }
KeyQtFontStyle::Key192 Key(const Key &o) : style(o.style), weight(o.weight), stretch(o.stretch) { }
193 uint style : 2;
194 signed int weight : 8;
195 signed int stretch : 12;
196
operator ==QtFontStyle::Key197 bool operator==(const Key & other) {
198 return (style == other.style && weight == other.weight &&
199 (stretch == 0 || other.stretch == 0 || stretch == other.stretch));
200 }
operator !=QtFontStyle::Key201 bool operator!=(const Key &other) {
202 return !operator==(other);
203 }
operator <QtFontStyle::Key204 bool operator <(const Key &o) {
205 int x = (style << 12) + (weight << 14) + stretch;
206 int y = (o.style << 12) + (o.weight << 14) + o.stretch;
207 return (x < y);
208 }
209 };
210
QtFontStyleQtFontStyle211 QtFontStyle(const Key &k)
212 : key(k), bitmapScalable(false), smoothScalable(false),
213 count(0), pixelSizes(nullptr)
214 {
215 }
216
~QtFontStyleQtFontStyle217 ~QtFontStyle() {
218 while (count) {
219 // bitfield count-- in while condition does not work correctly in mwccsym2
220 count--;
221 QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
222 if (integration) {
223 integration->fontDatabase()->releaseHandle(pixelSizes[count].handle);
224 }
225 }
226 free(pixelSizes);
227 }
228
229 Key key;
230 bool bitmapScalable : 1;
231 bool smoothScalable : 1;
232 signed int count : 30;
233 QtFontSize *pixelSizes;
234 QString styleName;
235
236 bool antialiased;
237
238 QtFontSize *pixelSize(unsigned short size, bool = false);
239 };
240
Key(const QString & styleString)241 QtFontStyle::Key::Key(const QString &styleString)
242 : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0)
243 {
244 weight = getFontWeight(styleString);
245
246 if (!styleString.isEmpty()) {
247 // First the straightforward no-translation checks, these are fast.
248 if (styleString.contains(QLatin1String("Italic")))
249 style = QFont::StyleItalic;
250 else if (styleString.contains(QLatin1String("Oblique")))
251 style = QFont::StyleOblique;
252
253 // Then the translation checks. These aren't as fast.
254 else if (styleString.contains(QCoreApplication::translate("QFontDatabase", "Italic")))
255 style = QFont::StyleItalic;
256 else if (styleString.contains(QCoreApplication::translate("QFontDatabase", "Oblique")))
257 style = QFont::StyleOblique;
258 }
259 }
260
pixelSize(unsigned short size,bool add)261 QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add)
262 {
263 for (int i = 0; i < count; i++) {
264 if (pixelSizes[i].pixelSize == size)
265 return pixelSizes + i;
266 }
267 if (!add)
268 return nullptr;
269
270 if (!pixelSizes) {
271 // Most style have only one font size, we avoid waisting memory
272 QtFontSize *newPixelSizes = (QtFontSize *)malloc(sizeof(QtFontSize));
273 Q_CHECK_PTR(newPixelSizes);
274 pixelSizes = newPixelSizes;
275 } else if (!(count % 8) || count == 1) {
276 QtFontSize *newPixelSizes = (QtFontSize *)
277 realloc(pixelSizes,
278 (((count+8) >> 3) << 3) * sizeof(QtFontSize));
279 Q_CHECK_PTR(newPixelSizes);
280 pixelSizes = newPixelSizes;
281 }
282 pixelSizes[count].pixelSize = size;
283 pixelSizes[count].handle = nullptr;
284 return pixelSizes + (count++);
285 }
286
287 struct QtFontFoundry
288 {
QtFontFoundryQtFontFoundry289 QtFontFoundry(const QString &n) : name(n), count(0), styles(nullptr) {}
~QtFontFoundryQtFontFoundry290 ~QtFontFoundry() {
291 while (count--)
292 delete styles[count];
293 free(styles);
294 }
295
296 QString name;
297
298 int count;
299 QtFontStyle **styles;
300 QtFontStyle *style(const QtFontStyle::Key &, const QString & = QString(), bool = false);
301 };
302
style(const QtFontStyle::Key & key,const QString & styleName,bool create)303 QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, const QString &styleName, bool create)
304 {
305 int pos = 0;
306 for (; pos < count; pos++) {
307 bool hasStyleName = !styleName.isEmpty(); // search styleName first if available
308 if (hasStyleName && !styles[pos]->styleName.isEmpty()) {
309 if (styles[pos]->styleName == styleName)
310 return styles[pos];
311 } else {
312 if (styles[pos]->key == key)
313 return styles[pos];
314 }
315 }
316 if (!create)
317 return nullptr;
318
319 // qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos);
320 if (!(count % 8)) {
321 QtFontStyle **newStyles = (QtFontStyle **)
322 realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *));
323 Q_CHECK_PTR(newStyles);
324 styles = newStyles;
325 }
326
327 QtFontStyle *style = new QtFontStyle(key);
328 style->styleName = styleName;
329 styles[pos] = style;
330 count++;
331 return styles[pos];
332 }
333
334
335 struct QtFontFamily
336 {
337 enum WritingSystemStatus {
338 Unknown = 0,
339 Supported = 1,
340 UnsupportedFT = 2,
341 Unsupported = UnsupportedFT
342 };
343
QtFontFamilyQtFontFamily344 QtFontFamily(const QString &n)
345 :
346 populated(false),
347 fixedPitch(false),
348 name(n), count(0), foundries(nullptr)
349 {
350 memset(writingSystems, 0, sizeof(writingSystems));
351 }
~QtFontFamilyQtFontFamily352 ~QtFontFamily() {
353 while (count--)
354 delete foundries[count];
355 free(foundries);
356 }
357
358 bool populated : 1;
359 bool fixedPitch : 1;
360
361 QString name;
362 QStringList aliases;
363 int count;
364 QtFontFoundry **foundries;
365
366 unsigned char writingSystems[QFontDatabase::WritingSystemsCount];
367
368 bool matchesFamilyName(const QString &familyName) const;
369 QtFontFoundry *foundry(const QString &f, bool = false);
370
371 void ensurePopulated();
372 };
373
foundry(const QString & f,bool create)374 QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create)
375 {
376 if (f.isNull() && count == 1)
377 return foundries[0];
378
379 for (int i = 0; i < count; i++) {
380 if (foundries[i]->name.compare(f, Qt::CaseInsensitive) == 0)
381 return foundries[i];
382 }
383 if (!create)
384 return nullptr;
385
386 if (!(count % 8)) {
387 QtFontFoundry **newFoundries = (QtFontFoundry **)
388 realloc(foundries,
389 (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *));
390 Q_CHECK_PTR(newFoundries);
391 foundries = newFoundries;
392 }
393
394 foundries[count] = new QtFontFoundry(f);
395 return foundries[count++];
396 }
397
equalsCaseInsensitive(const QString & a,const QString & b)398 static inline bool equalsCaseInsensitive(const QString &a, const QString &b)
399 {
400 return a.size() == b.size() && a.compare(b, Qt::CaseInsensitive) == 0;
401 }
402
matchesFamilyName(const QString & familyName) const403 bool QtFontFamily::matchesFamilyName(const QString &familyName) const
404 {
405 return equalsCaseInsensitive(name, familyName) || aliases.contains(familyName, Qt::CaseInsensitive);
406 }
407
ensurePopulated()408 void QtFontFamily::ensurePopulated()
409 {
410 if (populated)
411 return;
412
413 QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamily(name);
414 Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name));
415 }
416
417
418 struct FallbacksCacheKey {
419 QString family;
420 QFont::Style style;
421 QFont::StyleHint styleHint;
422 QChar::Script script;
423 };
424
operator ==(const FallbacksCacheKey & lhs,const FallbacksCacheKey & rhs)425 inline bool operator==(const FallbacksCacheKey &lhs, const FallbacksCacheKey &rhs) noexcept
426 {
427 return lhs.script == rhs.script &&
428 lhs.styleHint == rhs.styleHint &&
429 lhs.style == rhs.style &&
430 lhs.family == rhs.family;
431 }
432
operator !=(const FallbacksCacheKey & lhs,const FallbacksCacheKey & rhs)433 inline bool operator!=(const FallbacksCacheKey &lhs, const FallbacksCacheKey &rhs) noexcept
434 {
435 return !operator==(lhs, rhs);
436 }
437
qHash(const FallbacksCacheKey & key,uint seed=0)438 inline uint qHash(const FallbacksCacheKey &key, uint seed = 0) noexcept
439 {
440 QtPrivate::QHashCombine hash;
441 seed = hash(seed, key.family);
442 seed = hash(seed, int(key.style));
443 seed = hash(seed, int(key.styleHint));
444 seed = hash(seed, int(key.script));
445 return seed;
446 }
447
448
449 class QFontDatabasePrivate
450 {
451 public:
QFontDatabasePrivate()452 QFontDatabasePrivate()
453 : count(0), families(nullptr),
454 fallbacksCache(64)
455 { }
456
~QFontDatabasePrivate()457 ~QFontDatabasePrivate() {
458 free();
459 }
460
461 enum FamilyRequestFlags {
462 RequestFamily = 0,
463 EnsureCreated,
464 EnsurePopulated
465 };
466
467 QtFontFamily *family(const QString &f, FamilyRequestFlags flags = EnsurePopulated);
free()468 void free() {
469 while (count--)
470 delete families[count];
471 ::free(families);
472 families = nullptr;
473 count = 0;
474 // don't clear the memory fonts!
475 }
476
477 int count;
478 QtFontFamily **families;
479
480 QCache<FallbacksCacheKey, QStringList> fallbacksCache;
481
482
483 struct ApplicationFont {
484 QString fileName;
485 QByteArray data;
486 QStringList families;
487 };
488 QVector<ApplicationFont> applicationFonts;
489 int addAppFont(const QByteArray &fontData, const QString &fileName);
490 bool isApplicationFont(const QString &fileName);
491
492 void invalidate();
493 };
494 Q_DECLARE_TYPEINFO(QFontDatabasePrivate::ApplicationFont, Q_MOVABLE_TYPE);
495
invalidate()496 void QFontDatabasePrivate::invalidate()
497 {
498 QFontCache::instance()->clear();
499
500 fallbacksCache.clear();
501 free();
502 QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate();
503 emit static_cast<QGuiApplication *>(QCoreApplication::instance())->fontDatabaseChanged();
504 }
505
family(const QString & f,FamilyRequestFlags flags)506 QtFontFamily *QFontDatabasePrivate::family(const QString &f, FamilyRequestFlags flags)
507 {
508 QtFontFamily *fam = nullptr;
509
510 int low = 0;
511 int high = count;
512 int pos = count / 2;
513 int res = 1;
514 if (count) {
515 while ((res = families[pos]->name.compare(f, Qt::CaseInsensitive)) && pos != low) {
516 if (res > 0)
517 high = pos;
518 else
519 low = pos;
520 pos = (high + low) / 2;
521 }
522 if (!res)
523 fam = families[pos];
524 }
525
526 if (!fam && (flags & EnsureCreated)) {
527 if (res < 0)
528 pos++;
529
530 // qDebug() << "adding family " << f.toLatin1() << " at " << pos << " total=" << count;
531 if (!(count % 8)) {
532 QtFontFamily **newFamilies = (QtFontFamily **)
533 realloc(families,
534 (((count+8) >> 3) << 3) * sizeof(QtFontFamily *));
535 Q_CHECK_PTR(newFamilies);
536 families = newFamilies;
537 }
538
539 QtFontFamily *family = new QtFontFamily(f);
540 memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *));
541 families[pos] = family;
542 count++;
543
544 fam = families[pos];
545 }
546
547 if (fam && (flags & EnsurePopulated))
548 fam->ensurePopulated();
549
550 return fam;
551 }
552
553
554
555 static const int scriptForWritingSystem[] = {
556 QChar::Script_Common, // Any
557 QChar::Script_Latin, // Latin
558 QChar::Script_Greek, // Greek
559 QChar::Script_Cyrillic, // Cyrillic
560 QChar::Script_Armenian, // Armenian
561 QChar::Script_Hebrew, // Hebrew
562 QChar::Script_Arabic, // Arabic
563 QChar::Script_Syriac, // Syriac
564 QChar::Script_Thaana, // Thaana
565 QChar::Script_Devanagari, // Devanagari
566 QChar::Script_Bengali, // Bengali
567 QChar::Script_Gurmukhi, // Gurmukhi
568 QChar::Script_Gujarati, // Gujarati
569 QChar::Script_Oriya, // Oriya
570 QChar::Script_Tamil, // Tamil
571 QChar::Script_Telugu, // Telugu
572 QChar::Script_Kannada, // Kannada
573 QChar::Script_Malayalam, // Malayalam
574 QChar::Script_Sinhala, // Sinhala
575 QChar::Script_Thai, // Thai
576 QChar::Script_Lao, // Lao
577 QChar::Script_Tibetan, // Tibetan
578 QChar::Script_Myanmar, // Myanmar
579 QChar::Script_Georgian, // Georgian
580 QChar::Script_Khmer, // Khmer
581 QChar::Script_Han, // SimplifiedChinese
582 QChar::Script_Han, // TraditionalChinese
583 QChar::Script_Han, // Japanese
584 QChar::Script_Hangul, // Korean
585 QChar::Script_Latin, // Vietnamese
586 QChar::Script_Common, // Symbol
587 QChar::Script_Ogham, // Ogham
588 QChar::Script_Runic, // Runic
589 QChar::Script_Nko // Nko
590 };
591
592 Q_STATIC_ASSERT(sizeof(scriptForWritingSystem) / sizeof(scriptForWritingSystem[0]) == QFontDatabase::WritingSystemsCount);
593
qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem)594 Q_GUI_EXPORT int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem)
595 {
596 return scriptForWritingSystem[writingSystem];
597 }
598
599
600
601
602 /*!
603 \internal
604
605 This makes sense of the font family name:
606
607 if the family name contains a '[' and a ']', then we take the text
608 between the square brackets as the foundry, and the text before the
609 square brackets as the family (ie. "Arial [Monotype]")
610 */
parseFontName(const QString & name,QString & foundry,QString & family)611 static void parseFontName(const QString &name, QString &foundry, QString &family)
612 {
613 int i = name.indexOf(QLatin1Char('['));
614 int li = name.lastIndexOf(QLatin1Char(']'));
615 if (i >= 0 && li >= 0 && i < li) {
616 foundry = name.mid(i + 1, li - i - 1);
617 if (i > 0 && name[i - 1] == QLatin1Char(' '))
618 i--;
619 family = name.left(i);
620 } else {
621 foundry.clear();
622 family = name;
623 }
624
625 // capitalize the family/foundry names
626 bool space = true;
627 QChar *s = family.data();
628 int len = family.length();
629 while(len--) {
630 if (space) *s = s->toUpper();
631 space = s->isSpace();
632 ++s;
633 }
634
635 space = true;
636 s = foundry.data();
637 len = foundry.length();
638 while(len--) {
639 if (space) *s = s->toUpper();
640 space = s->isSpace();
641 ++s;
642 }
643 }
644
645
646 struct QtFontDesc
647 {
QtFontDescQtFontDesc648 inline QtFontDesc() : family(nullptr), foundry(nullptr), style(nullptr), size(nullptr) {}
649 QtFontFamily *family;
650 QtFontFoundry *foundry;
651 QtFontStyle *style;
652 QtFontSize *size;
653 };
654
initFontDef(const QtFontDesc & desc,const QFontDef & request,QFontDef * fontDef,bool multi)655 static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi)
656 {
657 fontDef->family = desc.family->name;
658 if (! desc.foundry->name.isEmpty() && desc.family->count > 1)
659 fontDef->family += QLatin1String(" [") + desc.foundry->name + QLatin1Char(']');
660
661 if (desc.style->smoothScalable
662 || QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable()
663 || (desc.style->bitmapScalable && (request.styleStrategy & QFont::PreferMatch))) {
664 fontDef->pixelSize = request.pixelSize;
665 } else {
666 fontDef->pixelSize = desc.size->pixelSize;
667 }
668 fontDef->pointSize = request.pointSize;
669
670 fontDef->styleHint = request.styleHint;
671 fontDef->styleStrategy = request.styleStrategy;
672
673 if (!multi)
674 fontDef->weight = desc.style->key.weight;
675 if (!multi)
676 fontDef->style = desc.style->key.style;
677 fontDef->fixedPitch = desc.family->fixedPitch;
678 fontDef->ignorePitch = false;
679 }
680
familyList(const QFontDef & req)681 static QStringList familyList(const QFontDef &req)
682 {
683 // list of families to try
684 QStringList family_list;
685
686 family_list << req.families;
687 if (!req.family.isEmpty()) {
688 const auto list = req.family.splitRef(QLatin1Char(','));
689 const int numFamilies = list.size();
690 family_list.reserve(numFamilies);
691 for (int i = 0; i < numFamilies; ++i) {
692 QStringRef str = list.at(i).trimmed();
693 if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
694 || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
695 str = str.mid(1, str.length() - 2);
696 if (!family_list.contains(str))
697 family_list << str.toString();
698 }
699 }
700 // append the substitute list for each family in family_list
701 for (int i = 0, size = family_list.size(); i < size; ++i)
702 family_list += QFont::substitutes(family_list.at(i));
703
704 return family_list;
705 }
706
Q_GLOBAL_STATIC(QFontDatabasePrivate,privateDb)707 Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
708 Q_GLOBAL_STATIC(QRecursiveMutex, fontDatabaseMutex)
709
710 // used in qguiapplication.cpp
711 void qt_cleanupFontDatabase()
712 {
713 QFontDatabasePrivate *db = privateDb();
714 if (db) {
715 db->fallbacksCache.clear();
716 db->free();
717 }
718 }
719
720 // used in qfont.cpp
qt_fontdatabase_mutex()721 QRecursiveMutex *qt_fontdatabase_mutex()
722 {
723 return fontDatabaseMutex();
724 }
725
726
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)727 void qt_registerFont(const QString &familyName, const QString &stylename,
728 const QString &foundryname, int weight,
729 QFont::Style style, int stretch, bool antialiased,
730 bool scalable, int pixelSize, bool fixedPitch,
731 const QSupportedWritingSystems &writingSystems, void *handle)
732 {
733 QFontDatabasePrivate *d = privateDb();
734 qCDebug(lcFontDb) << "Adding font: familyName" << familyName << "stylename" << stylename << "weight" << weight
735 << "style" << style << "pixelSize" << pixelSize << "antialiased" << antialiased << "fixed" << fixedPitch;
736 QtFontStyle::Key styleKey;
737 styleKey.style = style;
738 styleKey.weight = weight;
739 styleKey.stretch = stretch;
740 QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::EnsureCreated);
741 f->fixedPitch = fixedPitch;
742
743 for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
744 if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
745 f->writingSystems[i] = QtFontFamily::Supported;
746 }
747
748 QtFontFoundry *foundry = f->foundry(foundryname, true);
749 QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
750 fontStyle->smoothScalable = scalable;
751 fontStyle->antialiased = antialiased;
752 QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
753 if (size->handle) {
754 QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
755 if (integration)
756 integration->fontDatabase()->releaseHandle(size->handle);
757 }
758 size->handle = handle;
759 f->populated = true;
760 }
761
qt_registerFontFamily(const QString & familyName)762 void qt_registerFontFamily(const QString &familyName)
763 {
764 // Create uninitialized/unpopulated family
765 privateDb()->family(familyName, QFontDatabasePrivate::EnsureCreated);
766 }
767
qt_registerAliasToFontFamily(const QString & familyName,const QString & alias)768 void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
769 {
770 if (alias.isEmpty())
771 return;
772
773 QFontDatabasePrivate *d = privateDb();
774 QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
775 if (!f)
776 return;
777
778 if (f->aliases.contains(alias, Qt::CaseInsensitive))
779 return;
780
781 f->aliases.push_back(alias);
782 }
783
qt_resolveFontFamilyAlias(const QString & alias)784 QString qt_resolveFontFamilyAlias(const QString &alias)
785 {
786 if (!alias.isEmpty()) {
787 const QFontDatabasePrivate *d = privateDb();
788 for (int i = 0; i < d->count; ++i)
789 if (d->families[i]->matchesFamilyName(alias))
790 return d->families[i]->name;
791 }
792 return alias;
793 }
794
qt_isFontFamilyPopulated(const QString & familyName)795 bool qt_isFontFamilyPopulated(const QString &familyName)
796 {
797 QFontDatabasePrivate *d = privateDb();
798 QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
799 return f != nullptr && f->populated;
800 }
801
802 /*!
803 Returns a list of alternative fonts for the specified \a family and
804 \a style and \a script using the \a styleHint given.
805
806 Default implementation returns a list of fonts for which \a style and \a script support
807 has been reported during the font database population.
808 */
fallbacksForFamily(const QString & family,QFont::Style style,QFont::StyleHint styleHint,QChar::Script script) const809 QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
810 {
811 Q_UNUSED(family);
812 Q_UNUSED(styleHint);
813
814 QStringList preferredFallbacks;
815 QStringList otherFallbacks;
816
817 size_t writingSystem = std::find(scriptForWritingSystem,
818 scriptForWritingSystem + QFontDatabase::WritingSystemsCount,
819 script) - scriptForWritingSystem;
820 if (writingSystem >= QFontDatabase::WritingSystemsCount)
821 writingSystem = QFontDatabase::Any;
822
823 QFontDatabasePrivate *db = privateDb();
824 for (int i = 0; i < db->count; ++i) {
825 QtFontFamily *f = db->families[i];
826
827 f->ensurePopulated();
828
829 if (writingSystem > QFontDatabase::Any && f->writingSystems[writingSystem] != QtFontFamily::Supported)
830 continue;
831
832 for (int j = 0; j < f->count; ++j) {
833 QtFontFoundry *foundry = f->foundries[j];
834
835 for (int k = 0; k < foundry->count; ++k) {
836 QString name = foundry->name.isEmpty()
837 ? f->name
838 : f->name + QLatin1String(" [") + foundry->name + QLatin1Char(']');
839 if (style == foundry->styles[k]->key.style)
840 preferredFallbacks.append(name);
841 else
842 otherFallbacks.append(name);
843 }
844 }
845 }
846
847 return preferredFallbacks + otherFallbacks;
848 }
849
850 static void initializeDb();
851
fallbacksForFamily(const QString & family,QFont::Style style,QFont::StyleHint styleHint,QChar::Script script)852 static QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
853 {
854 QFontDatabasePrivate *db = privateDb();
855 if (!db->count)
856 initializeDb();
857
858 const FallbacksCacheKey cacheKey = { family, style, styleHint, script };
859
860 if (const QStringList *fallbacks = db->fallbacksCache.object(cacheKey))
861 return *fallbacks;
862
863 // make sure that the db has all fallback families
864 QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
865
866 QStringList::iterator i;
867 for (i = retList.begin(); i != retList.end(); ++i) {
868 bool contains = false;
869 for (int j = 0; j < db->count; j++) {
870 if (db->families[j]->matchesFamilyName(*i)) {
871 contains = true;
872 break;
873 }
874 }
875 if (!contains) {
876 i = retList.erase(i);
877 --i;
878 }
879 }
880
881 db->fallbacksCache.insert(cacheKey, new QStringList(retList));
882
883 return retList;
884 }
885
qt_fallbacksForFamily(const QString & family,QFont::Style style,QFont::StyleHint styleHint,QChar::Script script)886 QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
887 {
888 QMutexLocker locker(fontDatabaseMutex());
889 return fallbacksForFamily(family, style, styleHint, script);
890 }
891
892 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
893
initializeDb()894 static void initializeDb()
895 {
896 QFontDatabasePrivate *db = privateDb();
897
898 // init by asking for the platformfontdb for the first time or after invalidation
899 if (!db->count) {
900 QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
901 for (int i = 0; i < db->applicationFonts.count(); i++) {
902 if (!db->applicationFonts.at(i).families.isEmpty())
903 registerFont(&db->applicationFonts[i]);
904 }
905 }
906 }
907
load(const QString &=QString (),int=-1)908 static inline void load(const QString & = QString(), int = -1)
909 {
910 // Only initialize the database if it has been cleared or not initialized yet
911 if (!privateDb()->count)
912 initializeDb();
913 }
914
915 static
loadSingleEngine(int script,const QFontDef & request,QtFontFamily * family,QtFontFoundry * foundry,QtFontStyle * style,QtFontSize * size)916 QFontEngine *loadSingleEngine(int script,
917 const QFontDef &request,
918 QtFontFamily *family, QtFontFoundry *foundry,
919 QtFontStyle *style, QtFontSize *size)
920 {
921 Q_UNUSED(foundry);
922
923 Q_ASSERT(size);
924 QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
925 int pixelSize = size->pixelSize;
926 if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE)
927 || pfdb->fontsAlwaysScalable()) {
928 pixelSize = request.pixelSize;
929 }
930
931 QFontDef def = request;
932 def.pixelSize = pixelSize;
933
934 QFontCache *fontCache = QFontCache::instance();
935
936 QFontCache::Key key(def,script);
937 QFontEngine *engine = fontCache->findEngine(key);
938 if (!engine) {
939 const bool cacheForCommonScript = script != QChar::Script_Common
940 && (family->writingSystems[QFontDatabase::Latin] & QtFontFamily::Supported) != 0;
941
942 if (Q_LIKELY(cacheForCommonScript)) {
943 // fast path: check if engine was loaded for another script
944 key.script = QChar::Script_Common;
945 engine = fontCache->findEngine(key);
946 key.script = script;
947 if (engine) {
948 // Also check for OpenType tables when using complex scripts
949 if (Q_UNLIKELY(!engine->supportsScript(QChar::Script(script)))) {
950 qWarning(" OpenType support missing for \"%s\", script %d",
951 qPrintable(def.family), script);
952 return nullptr;
953 }
954
955 engine->isSmoothlyScalable = style->smoothScalable;
956 fontCache->insertEngine(key, engine);
957 return engine;
958 }
959 }
960
961 // To avoid synthesized stretch we need a matching stretch to be 100 after this point.
962 // If stretch didn't match exactly we need to calculate the new stretch factor.
963 // This only done if not matched by styleName.
964 if (style->key.stretch != 0 && request.stretch != 0
965 && (request.styleName.isEmpty() || request.styleName != style->styleName)) {
966 def.stretch = (request.stretch * 100 + style->key.stretch / 2) / style->key.stretch;
967 } else if (request.stretch == QFont::AnyStretch) {
968 def.stretch = 100;
969 }
970
971 engine = pfdb->fontEngine(def, size->handle);
972 if (engine) {
973 // Also check for OpenType tables when using complex scripts
974 if (!engine->supportsScript(QChar::Script(script))) {
975 qWarning(" OpenType support missing for \"%s\", script %d",
976 + qPrintable(def.family), script);
977 if (engine->ref.loadRelaxed() == 0)
978 delete engine;
979 return nullptr;
980 }
981
982 engine->isSmoothlyScalable = style->smoothScalable;
983 fontCache->insertEngine(key, engine);
984
985 if (Q_LIKELY(cacheForCommonScript && !engine->symbol)) {
986 // cache engine for Common script as well
987 key.script = QChar::Script_Common;
988 if (!fontCache->findEngine(key))
989 fontCache->insertEngine(key, engine);
990 }
991 }
992 }
993 return engine;
994 }
995
996 static
loadEngine(int script,const QFontDef & request,QtFontFamily * family,QtFontFoundry * foundry,QtFontStyle * style,QtFontSize * size)997 QFontEngine *loadEngine(int script, const QFontDef &request,
998 QtFontFamily *family, QtFontFoundry *foundry,
999 QtFontStyle *style, QtFontSize *size)
1000 {
1001 QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size);
1002
1003 if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
1004 Q_TRACE(QFontDatabase_loadEngine, request.family, request.pointSize);
1005
1006 QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
1007 QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script));
1008 if (!request.fallBackFamilies.isEmpty()) {
1009 QStringList fallbacks = request.fallBackFamilies;
1010
1011 QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
1012 if (styleHint == QFont::AnyStyle && request.fixedPitch)
1013 styleHint = QFont::TypeWriter;
1014
1015 fallbacks += fallbacksForFamily(family->name, QFont::Style(style->key.style), styleHint, QChar::Script(script));
1016
1017 pfMultiEngine->setFallbackFamiliesList(fallbacks);
1018 }
1019 engine = pfMultiEngine;
1020
1021 // Cache Multi font engine as well in case we got the single
1022 // font engine when we are actually looking for a Multi one
1023 QFontCache::Key key(request, script, 1);
1024 QFontCache::instance()->insertEngine(key, engine);
1025 }
1026
1027 return engine;
1028 }
1029
registerFont(QFontDatabasePrivate::ApplicationFont * fnt)1030 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
1031 {
1032 fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName);
1033 }
1034
bestStyle(QtFontFoundry * foundry,const QtFontStyle::Key & styleKey,const QString & styleName=QString ())1035 static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey,
1036 const QString &styleName = QString())
1037 {
1038 int best = 0;
1039 int dist = 0xffff;
1040
1041 for ( int i = 0; i < foundry->count; i++ ) {
1042 QtFontStyle *style = foundry->styles[i];
1043
1044 if (!styleName.isEmpty() && styleName == style->styleName) {
1045 dist = 0;
1046 best = i;
1047 break;
1048 }
1049
1050 int d = qAbs( styleKey.weight - style->key.weight );
1051
1052 if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
1053 d += qAbs( styleKey.stretch - style->key.stretch );
1054 }
1055
1056 if (styleKey.style != style->key.style) {
1057 if (styleKey.style != QFont::StyleNormal && style->key.style != QFont::StyleNormal)
1058 // one is italic, the other oblique
1059 d += 0x0001;
1060 else
1061 d += 0x1000;
1062 }
1063
1064 if ( d < dist ) {
1065 best = i;
1066 dist = d;
1067 }
1068 }
1069
1070 qCDebug(lcFontMatch, " best style has distance 0x%x", dist );
1071 return foundry->styles[best];
1072 }
1073
1074
1075 static
bestFoundry(int script,unsigned int score,int styleStrategy,const QtFontFamily * family,const QString & foundry_name,QtFontStyle::Key styleKey,int pixelSize,char pitch,QtFontDesc * desc,const QString & styleName=QString ())1076 unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
1077 const QtFontFamily *family, const QString &foundry_name,
1078 QtFontStyle::Key styleKey, int pixelSize, char pitch,
1079 QtFontDesc *desc, const QString &styleName = QString())
1080 {
1081 Q_UNUSED(script);
1082 Q_UNUSED(pitch);
1083
1084 desc->foundry = nullptr;
1085 desc->style = nullptr;
1086 desc->size = nullptr;
1087
1088
1089 qCDebug(lcFontMatch, " REMARK: looking for best foundry for family '%s' [%d]", family->name.toLatin1().constData(), family->count);
1090
1091 for (int x = 0; x < family->count; ++x) {
1092 QtFontFoundry *foundry = family->foundries[x];
1093 if (!foundry_name.isEmpty() && foundry->name.compare(foundry_name, Qt::CaseInsensitive) != 0)
1094 continue;
1095
1096 qCDebug(lcFontMatch, " looking for matching style in foundry '%s' %d",
1097 foundry->name.isEmpty() ? "-- none --" : foundry->name.toLatin1().constData(), foundry->count);
1098
1099 QtFontStyle *style = bestStyle(foundry, styleKey, styleName);
1100
1101 if (!style->smoothScalable && (styleStrategy & QFont::ForceOutline)) {
1102 qCDebug(lcFontMatch, " ForceOutline set, but not smoothly scalable");
1103 continue;
1104 }
1105
1106 int px = -1;
1107 QtFontSize *size = nullptr;
1108
1109 // 1. see if we have an exact matching size
1110 if (!(styleStrategy & QFont::ForceOutline)) {
1111 size = style->pixelSize(pixelSize);
1112 if (size) {
1113 qCDebug(lcFontMatch, " found exact size match (%d pixels)", size->pixelSize);
1114 px = size->pixelSize;
1115 }
1116 }
1117
1118 // 2. see if we have a smoothly scalable font
1119 if (!size && style->smoothScalable && ! (styleStrategy & QFont::PreferBitmap)) {
1120 size = style->pixelSize(SMOOTH_SCALABLE);
1121 if (size) {
1122 qCDebug(lcFontMatch, " found smoothly scalable font (%d pixels)", pixelSize);
1123 px = pixelSize;
1124 }
1125 }
1126
1127 // 3. see if we have a bitmap scalable font
1128 if (!size && style->bitmapScalable && (styleStrategy & QFont::PreferMatch)) {
1129 size = style->pixelSize(0);
1130 if (size) {
1131 qCDebug(lcFontMatch, " found bitmap scalable font (%d pixels)", pixelSize);
1132 px = pixelSize;
1133 }
1134 }
1135
1136
1137 // 4. find closest size match
1138 if (! size) {
1139 unsigned int distance = ~0u;
1140 for (int x = 0; x < style->count; ++x) {
1141
1142 unsigned int d;
1143 if (style->pixelSizes[x].pixelSize < pixelSize) {
1144 // penalize sizes that are smaller than the
1145 // requested size, due to truncation from floating
1146 // point to integer conversions
1147 d = pixelSize - style->pixelSizes[x].pixelSize + 1;
1148 } else {
1149 d = style->pixelSizes[x].pixelSize - pixelSize;
1150 }
1151
1152 if (d < distance) {
1153 distance = d;
1154 size = style->pixelSizes + x;
1155 qCDebug(lcFontMatch, " best size so far: %3d (%d)", size->pixelSize, pixelSize);
1156 }
1157 }
1158
1159 if (!size) {
1160 qCDebug(lcFontMatch, " no size supports the script we want");
1161 continue;
1162 }
1163
1164 if (style->bitmapScalable && ! (styleStrategy & QFont::PreferQuality) &&
1165 (distance * 10 / pixelSize) >= 2) {
1166 // the closest size is not close enough, go ahead and
1167 // use a bitmap scaled font
1168 size = style->pixelSize(0);
1169 px = pixelSize;
1170 } else {
1171 px = size->pixelSize;
1172 }
1173 }
1174
1175
1176 unsigned int this_score = 0x0000;
1177 enum {
1178 PitchMismatch = 0x4000,
1179 StyleMismatch = 0x2000,
1180 BitmapScaledPenalty = 0x1000
1181 };
1182 if (pitch != '*') {
1183 if ((pitch == 'm' && !family->fixedPitch)
1184 || (pitch == 'p' && family->fixedPitch))
1185 this_score += PitchMismatch;
1186 }
1187 if (styleKey != style->key)
1188 this_score += StyleMismatch;
1189 if (!style->smoothScalable && px != size->pixelSize) // bitmap scaled
1190 this_score += BitmapScaledPenalty;
1191 if (px != pixelSize) // close, but not exact, size match
1192 this_score += qAbs(px - pixelSize);
1193
1194 if (this_score < score) {
1195 qCDebug(lcFontMatch, " found a match: score %x best score so far %x",
1196 this_score, score);
1197
1198 score = this_score;
1199 desc->foundry = foundry;
1200 desc->style = style;
1201 desc->size = size;
1202 } else {
1203 qCDebug(lcFontMatch, " score %x no better than best %x", this_score, score);
1204 }
1205 }
1206
1207 return score;
1208 }
1209
matchFamilyName(const QString & familyName,QtFontFamily * f)1210 static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
1211 {
1212 if (familyName.isEmpty())
1213 return true;
1214 return f->matchesFamilyName(familyName);
1215 }
1216
1217 /*!
1218 \internal
1219
1220 Tries to find the best match for a given request and family/foundry
1221 */
match(int script,const QFontDef & request,const QString & family_name,const QString & foundry_name,QtFontDesc * desc,const QList<int> & blacklistedFamilies)1222 static int match(int script, const QFontDef &request,
1223 const QString &family_name, const QString &foundry_name,
1224 QtFontDesc *desc, const QList<int> &blacklistedFamilies)
1225 {
1226 int result = -1;
1227
1228 QtFontStyle::Key styleKey;
1229 styleKey.style = request.style;
1230 styleKey.weight = request.weight;
1231 // Prefer a stretch closest to 100.
1232 styleKey.stretch = request.stretch ? request.stretch : 100;
1233 char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
1234
1235
1236 qCDebug(lcFontMatch, "QFontDatabase::match\n"
1237 " request:\n"
1238 " family: %s [%s], script: %d\n"
1239 " weight: %d, style: %d\n"
1240 " stretch: %d\n"
1241 " pixelSize: %g\n"
1242 " pitch: %c",
1243 family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
1244 foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
1245 script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
1246
1247 desc->family = nullptr;
1248 desc->foundry = nullptr;
1249 desc->style = nullptr;
1250 desc->size = nullptr;
1251
1252 unsigned int score = ~0u;
1253
1254 load(family_name, script);
1255
1256 size_t writingSystem = std::find(scriptForWritingSystem, scriptForWritingSystem +
1257 QFontDatabase::WritingSystemsCount, script) - scriptForWritingSystem;
1258 if (writingSystem >= QFontDatabase::WritingSystemsCount)
1259 writingSystem = QFontDatabase::Any;
1260
1261 QFontDatabasePrivate *db = privateDb();
1262 for (int x = 0; x < db->count; ++x) {
1263 if (blacklistedFamilies.contains(x))
1264 continue;
1265 QtFontDesc test;
1266 test.family = db->families[x];
1267
1268 if (!matchFamilyName(family_name, test.family))
1269 continue;
1270
1271 test.family->ensurePopulated();
1272
1273 // Check if family is supported in the script we want
1274 if (writingSystem != QFontDatabase::Any && !(test.family->writingSystems[writingSystem] & QtFontFamily::Supported))
1275 continue;
1276
1277 // as we know the script is supported, we can be sure
1278 // to find a matching font here.
1279 unsigned int newscore =
1280 bestFoundry(script, score, request.styleStrategy,
1281 test.family, foundry_name, styleKey, request.pixelSize, pitch,
1282 &test, request.styleName);
1283 if (test.foundry == nullptr && !foundry_name.isEmpty()) {
1284 // the specific foundry was not found, so look for
1285 // any foundry matching our requirements
1286 newscore = bestFoundry(script, score, request.styleStrategy, test.family,
1287 QString(), styleKey, request.pixelSize,
1288 pitch, &test, request.styleName);
1289 }
1290
1291 if (newscore < score) {
1292 result = x;
1293 score = newscore;
1294 *desc = test;
1295 }
1296 if (newscore < 10) // xlfd instead of FT... just accept it
1297 break;
1298 }
1299 return result;
1300 }
1301
styleStringHelper(int weight,QFont::Style style)1302 static QString styleStringHelper(int weight, QFont::Style style)
1303 {
1304 QString result;
1305 if (weight > QFont::Normal) {
1306 if (weight >= QFont::Black)
1307 result = QCoreApplication::translate("QFontDatabase", "Black");
1308 else if (weight >= QFont::ExtraBold)
1309 result = QCoreApplication::translate("QFontDatabase", "Extra Bold");
1310 else if (weight >= QFont::Bold)
1311 result = QCoreApplication::translate("QFontDatabase", "Bold");
1312 else if (weight >= QFont::DemiBold)
1313 result = QCoreApplication::translate("QFontDatabase", "Demi Bold");
1314 else if (weight >= QFont::Medium)
1315 result = QCoreApplication::translate("QFontDatabase", "Medium", "The Medium font weight");
1316 } else {
1317 if (weight <= QFont::Thin)
1318 result = QCoreApplication::translate("QFontDatabase", "Thin");
1319 else if (weight <= QFont::ExtraLight)
1320 result = QCoreApplication::translate("QFontDatabase", "Extra Light");
1321 else if (weight <= QFont::Light)
1322 result = QCoreApplication::translate("QFontDatabase", "Light");
1323 }
1324
1325 if (style == QFont::StyleItalic)
1326 result += QLatin1Char(' ') + QCoreApplication::translate("QFontDatabase", "Italic");
1327 else if (style == QFont::StyleOblique)
1328 result += QLatin1Char(' ') + QCoreApplication::translate("QFontDatabase", "Oblique");
1329
1330 if (result.isEmpty())
1331 result = QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight");
1332
1333 return result.simplified();
1334 }
1335
1336 /*!
1337 Returns a string that describes the style of the \a font. For
1338 example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
1339 string may be returned.
1340 */
styleString(const QFont & font)1341 QString QFontDatabase::styleString(const QFont &font)
1342 {
1343 return font.styleName().isEmpty() ? styleStringHelper(font.weight(), font.style())
1344 : font.styleName();
1345 }
1346
1347 /*!
1348 Returns a string that describes the style of the \a fontInfo. For
1349 example, "Bold Italic", "Bold", "Italic" or "Normal". An empty
1350 string may be returned.
1351 */
styleString(const QFontInfo & fontInfo)1352 QString QFontDatabase::styleString(const QFontInfo &fontInfo)
1353 {
1354 return fontInfo.styleName().isEmpty() ? styleStringHelper(fontInfo.weight(), fontInfo.style())
1355 : fontInfo.styleName();
1356 }
1357
1358
1359 /*!
1360 \class QFontDatabase
1361 \threadsafe
1362 \inmodule QtGui
1363
1364 \brief The QFontDatabase class provides information about the fonts available in the underlying window system.
1365
1366 \ingroup appearance
1367
1368 The most common uses of this class are to query the database for
1369 the list of font families() and for the pointSizes() and styles()
1370 that are available for each family. An alternative to pointSizes()
1371 is smoothSizes() which returns the sizes at which a given family
1372 and style will look attractive.
1373
1374 If the font family is available from two or more foundries the
1375 foundry name is included in the family name; for example:
1376 "Helvetica [Adobe]" and "Helvetica [Cronyx]". When you specify a
1377 family, you can either use the old hyphenated "foundry-family"
1378 format or the bracketed "family [foundry]" format; for example:
1379 "Cronyx-Helvetica" or "Helvetica [Cronyx]". If the family has a
1380 foundry it is always returned using the bracketed format, as is
1381 the case with the value returned by families().
1382
1383 The font() function returns a QFont given a family, style and
1384 point size.
1385
1386 A family and style combination can be checked to see if it is
1387 italic() or bold(), and to retrieve its weight(). Similarly we can
1388 call isBitmapScalable(), isSmoothlyScalable(), isScalable() and
1389 isFixedPitch().
1390
1391 Use the styleString() to obtain a text version of a style.
1392
1393 The QFontDatabase class also supports some static functions, for
1394 example, standardSizes(). You can retrieve the description of a
1395 writing system using writingSystemName(), and a sample of
1396 characters in a writing system with writingSystemSample().
1397
1398 Example:
1399
1400 \snippet qfontdatabase/main.cpp 0
1401 \snippet qfontdatabase/main.cpp 1
1402
1403 This example gets the list of font families, the list of
1404 styles for each family, and the point sizes that are available for
1405 each combination of family and style, displaying this information
1406 in a tree view.
1407
1408 \sa QFont, QFontInfo, QFontMetrics, {Character Map Example}
1409 */
1410
1411 /*!
1412 Creates a font database object.
1413 */
QFontDatabase()1414 QFontDatabase::QFontDatabase()
1415 {
1416 if (Q_UNLIKELY(!qApp || !QGuiApplicationPrivate::platformIntegration()))
1417 qFatal("QFontDatabase: Must construct a QGuiApplication before accessing QFontDatabase");
1418
1419 QMutexLocker locker(fontDatabaseMutex());
1420 createDatabase();
1421 d = privateDb();
1422 }
1423
1424 /*!
1425 \enum QFontDatabase::WritingSystem
1426
1427 \value Any
1428 \value Latin
1429 \value Greek
1430 \value Cyrillic
1431 \value Armenian
1432 \value Hebrew
1433 \value Arabic
1434 \value Syriac
1435 \value Thaana
1436 \value Devanagari
1437 \value Bengali
1438 \value Gurmukhi
1439 \value Gujarati
1440 \value Oriya
1441 \value Tamil
1442 \value Telugu
1443 \value Kannada
1444 \value Malayalam
1445 \value Sinhala
1446 \value Thai
1447 \value Lao
1448 \value Tibetan
1449 \value Myanmar
1450 \value Georgian
1451 \value Khmer
1452 \value SimplifiedChinese
1453 \value TraditionalChinese
1454 \value Japanese
1455 \value Korean
1456 \value Vietnamese
1457 \value Symbol
1458 \value Other (the same as Symbol)
1459 \value Ogham
1460 \value Runic
1461 \value Nko
1462
1463 \omitvalue WritingSystemsCount
1464 */
1465
1466 /*!
1467 \enum QFontDatabase::SystemFont
1468
1469 \value GeneralFont The default system font.
1470 \value FixedFont The fixed font that the system recommends.
1471 \value TitleFont The system standard font for titles.
1472 \value SmallestReadableFont The smallest readable system font.
1473
1474 \since 5.2
1475 */
1476
1477 /*!
1478 Returns a sorted list of the available writing systems. This is
1479 list generated from information about all installed fonts on the
1480 system.
1481
1482 \sa families()
1483 */
writingSystems() const1484 QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const
1485 {
1486 QMutexLocker locker(fontDatabaseMutex());
1487
1488 QT_PREPEND_NAMESPACE(load)();
1489
1490 quint64 writingSystemsFound = 0;
1491 Q_STATIC_ASSERT(WritingSystemsCount < 64);
1492
1493 for (int i = 0; i < d->count; ++i) {
1494 QtFontFamily *family = d->families[i];
1495 family->ensurePopulated();
1496
1497 if (family->count == 0)
1498 continue;
1499 for (uint x = Latin; x < uint(WritingSystemsCount); ++x) {
1500 if (family->writingSystems[x] & QtFontFamily::Supported)
1501 writingSystemsFound |= quint64(1) << x;
1502 }
1503 }
1504
1505 // mutex protection no longer needed - just working on local data now:
1506 locker.unlock();
1507
1508 QList<WritingSystem> list;
1509 list.reserve(qPopulationCount(writingSystemsFound));
1510 for (uint x = Latin ; x < uint(WritingSystemsCount); ++x) {
1511 if (writingSystemsFound & (quint64(1) << x))
1512 list.push_back(WritingSystem(x));
1513 }
1514 return list;
1515 }
1516
1517
1518 /*!
1519 Returns a sorted list of the writing systems supported by a given
1520 font \a family.
1521
1522 \sa families()
1523 */
writingSystems(const QString & family) const1524 QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family) const
1525 {
1526 QString familyName, foundryName;
1527 parseFontName(family, foundryName, familyName);
1528
1529 QMutexLocker locker(fontDatabaseMutex());
1530
1531 QT_PREPEND_NAMESPACE(load)();
1532
1533 QList<WritingSystem> list;
1534 QtFontFamily *f = d->family(familyName);
1535 if (!f || f->count == 0)
1536 return list;
1537
1538 for (int x = Latin; x < WritingSystemsCount; ++x) {
1539 const WritingSystem writingSystem = WritingSystem(x);
1540 if (f->writingSystems[writingSystem] & QtFontFamily::Supported)
1541 list.append(writingSystem);
1542 }
1543 return list;
1544 }
1545
1546
1547 /*!
1548 Returns a sorted list of the available font families which support
1549 the \a writingSystem.
1550
1551 If a family exists in several foundries, the returned name for
1552 that font is in the form "family [foundry]". Examples: "Times
1553 [Adobe]", "Times [Cronyx]", "Palatino".
1554
1555 \sa writingSystems()
1556 */
families(WritingSystem writingSystem) const1557 QStringList QFontDatabase::families(WritingSystem writingSystem) const
1558 {
1559 QMutexLocker locker(fontDatabaseMutex());
1560
1561 QT_PREPEND_NAMESPACE(load)();
1562
1563 QStringList flist;
1564 for (int i = 0; i < d->count; i++) {
1565 QtFontFamily *f = d->families[i];
1566 if (f->populated && f->count == 0)
1567 continue;
1568 if (writingSystem != Any) {
1569 f->ensurePopulated();
1570 if (f->writingSystems[writingSystem] != QtFontFamily::Supported)
1571 continue;
1572 }
1573 if (!f->populated || f->count == 1) {
1574 flist.append(f->name);
1575 } else {
1576 for (int j = 0; j < f->count; j++) {
1577 QString str = f->name;
1578 QString foundry = f->foundries[j]->name;
1579 if (!foundry.isEmpty()) {
1580 str += QLatin1String(" [");
1581 str += foundry;
1582 str += QLatin1Char(']');
1583 }
1584 flist.append(str);
1585 }
1586 }
1587 }
1588 return flist;
1589 }
1590
1591 /*!
1592 Returns a list of the styles available for the font family \a
1593 family. Some example styles: "Light", "Light Italic", "Bold",
1594 "Oblique", "Demi". The list may be empty.
1595
1596 \sa families()
1597 */
styles(const QString & family) const1598 QStringList QFontDatabase::styles(const QString &family) const
1599 {
1600 QString familyName, foundryName;
1601 parseFontName(family, foundryName, familyName);
1602
1603 QMutexLocker locker(fontDatabaseMutex());
1604
1605 QT_PREPEND_NAMESPACE(load)(familyName);
1606
1607 QStringList l;
1608 QtFontFamily *f = d->family(familyName);
1609 if (!f)
1610 return l;
1611
1612 QtFontFoundry allStyles(foundryName);
1613 for (int j = 0; j < f->count; j++) {
1614 QtFontFoundry *foundry = f->foundries[j];
1615 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1616 for (int k = 0; k < foundry->count; k++) {
1617 QtFontStyle::Key ke(foundry->styles[k]->key);
1618 ke.stretch = 0;
1619 allStyles.style(ke, foundry->styles[k]->styleName, true);
1620 }
1621 }
1622 }
1623
1624 l.reserve(allStyles.count);
1625 for (int i = 0; i < allStyles.count; i++) {
1626 l.append(allStyles.styles[i]->styleName.isEmpty() ?
1627 styleStringHelper(allStyles.styles[i]->key.weight,
1628 (QFont::Style)allStyles.styles[i]->key.style) :
1629 allStyles.styles[i]->styleName);
1630 }
1631 return l;
1632 }
1633
1634 /*!
1635 Returns \c true if the font that has family \a family and style \a
1636 style is fixed pitch; otherwise returns \c false.
1637 */
1638
isFixedPitch(const QString & family,const QString & style) const1639 bool QFontDatabase::isFixedPitch(const QString &family,
1640 const QString &style) const
1641 {
1642 Q_UNUSED(style);
1643
1644 QString familyName, foundryName;
1645 parseFontName(family, foundryName, familyName);
1646
1647 QMutexLocker locker(fontDatabaseMutex());
1648
1649 QT_PREPEND_NAMESPACE(load)(familyName);
1650
1651 QtFontFamily *f = d->family(familyName);
1652 return (f && f->fixedPitch);
1653 }
1654
1655 /*!
1656 Returns \c true if the font that has family \a family and style \a
1657 style is a scalable bitmap font; otherwise returns \c false. Scaling
1658 a bitmap font usually produces an unattractive hardly readable
1659 result, because the pixels of the font are scaled. If you need to
1660 scale a bitmap font it is better to scale it to one of the fixed
1661 sizes returned by smoothSizes().
1662
1663 \sa isScalable(), isSmoothlyScalable()
1664 */
isBitmapScalable(const QString & family,const QString & style) const1665 bool QFontDatabase::isBitmapScalable(const QString &family,
1666 const QString &style) const
1667 {
1668 bool bitmapScalable = false;
1669 QString familyName, foundryName;
1670 parseFontName(family, foundryName, familyName);
1671
1672 QMutexLocker locker(fontDatabaseMutex());
1673
1674 QT_PREPEND_NAMESPACE(load)(familyName);
1675
1676 QtFontFamily *f = d->family(familyName);
1677 if (!f) return bitmapScalable;
1678
1679 QtFontStyle::Key styleKey(style);
1680 for (int j = 0; j < f->count; j++) {
1681 QtFontFoundry *foundry = f->foundries[j];
1682 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1683 for (int k = 0; k < foundry->count; k++)
1684 if ((style.isEmpty() ||
1685 foundry->styles[k]->styleName == style ||
1686 foundry->styles[k]->key == styleKey)
1687 && foundry->styles[k]->bitmapScalable && !foundry->styles[k]->smoothScalable) {
1688 bitmapScalable = true;
1689 goto end;
1690 }
1691 }
1692 }
1693 end:
1694 return bitmapScalable;
1695 }
1696
1697
1698 /*!
1699 Returns \c true if the font that has family \a family and style \a
1700 style is smoothly scalable; otherwise returns \c false. If this
1701 function returns \c true, it's safe to scale this font to any size,
1702 and the result will always look attractive.
1703
1704 \sa isScalable(), isBitmapScalable()
1705 */
isSmoothlyScalable(const QString & family,const QString & style) const1706 bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style) const
1707 {
1708 bool smoothScalable = false;
1709 QString familyName, foundryName;
1710 parseFontName(family, foundryName, familyName);
1711
1712 QMutexLocker locker(fontDatabaseMutex());
1713
1714 QT_PREPEND_NAMESPACE(load)(familyName);
1715
1716 QtFontFamily *f = d->family(familyName);
1717 if (!f) {
1718 for (int i = 0; i < d->count; i++) {
1719 if (d->families[i]->matchesFamilyName(familyName)) {
1720 f = d->families[i];
1721 f->ensurePopulated();
1722 break;
1723 }
1724 }
1725 }
1726 if (!f) return smoothScalable;
1727
1728 QtFontStyle::Key styleKey(style);
1729 for (int j = 0; j < f->count; j++) {
1730 QtFontFoundry *foundry = f->foundries[j];
1731 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1732 for (int k = 0; k < foundry->count; k++)
1733 if ((style.isEmpty() ||
1734 foundry->styles[k]->styleName == style ||
1735 foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
1736 smoothScalable = true;
1737 goto end;
1738 }
1739 }
1740 }
1741 end:
1742 return smoothScalable;
1743 }
1744
1745 /*!
1746 Returns \c true if the font that has family \a family and style \a
1747 style is scalable; otherwise returns \c false.
1748
1749 \sa isBitmapScalable(), isSmoothlyScalable()
1750 */
isScalable(const QString & family,const QString & style) const1751 bool QFontDatabase::isScalable(const QString &family,
1752 const QString &style) const
1753 {
1754 QMutexLocker locker(fontDatabaseMutex());
1755 if (isSmoothlyScalable(family, style))
1756 return true;
1757 return isBitmapScalable(family, style);
1758 }
1759
1760
1761 /*!
1762 Returns a list of the point sizes available for the font that has
1763 family \a family and style \a styleName. The list may be empty.
1764
1765 \sa smoothSizes(), standardSizes()
1766 */
pointSizes(const QString & family,const QString & styleName)1767 QList<int> QFontDatabase::pointSizes(const QString &family,
1768 const QString &styleName)
1769 {
1770 if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
1771 return standardSizes();
1772
1773 bool smoothScalable = false;
1774 QString familyName, foundryName;
1775 parseFontName(family, foundryName, familyName);
1776
1777 QMutexLocker locker(fontDatabaseMutex());
1778
1779 QT_PREPEND_NAMESPACE(load)(familyName);
1780
1781 QList<int> sizes;
1782
1783 QtFontFamily *fam = d->family(familyName);
1784 if (!fam) return sizes;
1785
1786
1787 const int dpi = qt_defaultDpiY(); // embedded
1788
1789 QtFontStyle::Key styleKey(styleName);
1790 for (int j = 0; j < fam->count; j++) {
1791 QtFontFoundry *foundry = fam->foundries[j];
1792 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1793 QtFontStyle *style = foundry->style(styleKey, styleName);
1794 if (!style) continue;
1795
1796 if (style->smoothScalable) {
1797 smoothScalable = true;
1798 goto end;
1799 }
1800 for (int l = 0; l < style->count; l++) {
1801 const QtFontSize *size = style->pixelSizes + l;
1802
1803 if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
1804 const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
1805 if (! sizes.contains(pointSize))
1806 sizes.append(pointSize);
1807 }
1808 }
1809 }
1810 }
1811 end:
1812 if (smoothScalable)
1813 return standardSizes();
1814
1815 std::sort(sizes.begin(), sizes.end());
1816 return sizes;
1817 }
1818
1819 /*!
1820 Returns a QFont object that has family \a family, style \a style
1821 and point size \a pointSize. If no matching font could be created,
1822 a QFont object that uses the application's default font is
1823 returned.
1824 */
font(const QString & family,const QString & style,int pointSize) const1825 QFont QFontDatabase::font(const QString &family, const QString &style,
1826 int pointSize) const
1827 {
1828 QString familyName, foundryName;
1829 parseFontName(family, foundryName, familyName);
1830
1831 QMutexLocker locker(fontDatabaseMutex());
1832
1833 QT_PREPEND_NAMESPACE(load)(familyName);
1834
1835 QtFontFoundry allStyles(foundryName);
1836 QtFontFamily *f = d->family(familyName);
1837 if (!f) return QGuiApplication::font();
1838
1839 for (int j = 0; j < f->count; j++) {
1840 QtFontFoundry *foundry = f->foundries[j];
1841 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1842 for (int k = 0; k < foundry->count; k++)
1843 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1844 }
1845 }
1846
1847 QtFontStyle::Key styleKey(style);
1848 QtFontStyle *s = bestStyle(&allStyles, styleKey, style);
1849
1850 if (!s) // no styles found?
1851 return QGuiApplication::font();
1852
1853 QFont fnt(family, pointSize, s->key.weight);
1854 fnt.setStyle((QFont::Style)s->key.style);
1855 if (!s->styleName.isEmpty())
1856 fnt.setStyleName(s->styleName);
1857 return fnt;
1858 }
1859
1860
1861 /*!
1862 Returns the point sizes of a font that has family \a family and
1863 style \a styleName that will look attractive. The list may be empty.
1864 For non-scalable fonts and bitmap scalable fonts, this function
1865 is equivalent to pointSizes().
1866
1867 \sa pointSizes(), standardSizes()
1868 */
smoothSizes(const QString & family,const QString & styleName)1869 QList<int> QFontDatabase::smoothSizes(const QString &family,
1870 const QString &styleName)
1871 {
1872 if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
1873 return standardSizes();
1874
1875 bool smoothScalable = false;
1876 QString familyName, foundryName;
1877 parseFontName(family, foundryName, familyName);
1878
1879 QMutexLocker locker(fontDatabaseMutex());
1880
1881 QT_PREPEND_NAMESPACE(load)(familyName);
1882
1883 QList<int> sizes;
1884
1885 QtFontFamily *fam = d->family(familyName);
1886 if (!fam)
1887 return sizes;
1888
1889 const int dpi = qt_defaultDpiY(); // embedded
1890
1891 QtFontStyle::Key styleKey(styleName);
1892 for (int j = 0; j < fam->count; j++) {
1893 QtFontFoundry *foundry = fam->foundries[j];
1894 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1895 QtFontStyle *style = foundry->style(styleKey, styleName);
1896 if (!style) continue;
1897
1898 if (style->smoothScalable) {
1899 smoothScalable = true;
1900 goto end;
1901 }
1902 for (int l = 0; l < style->count; l++) {
1903 const QtFontSize *size = style->pixelSizes + l;
1904
1905 if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
1906 const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
1907 if (! sizes.contains(pointSize))
1908 sizes.append(pointSize);
1909 }
1910 }
1911 }
1912 }
1913 end:
1914 if (smoothScalable)
1915 return QFontDatabase::standardSizes();
1916
1917 std::sort(sizes.begin(), sizes.end());
1918 return sizes;
1919 }
1920
1921
1922 /*!
1923 Returns a list of standard font sizes.
1924
1925 \sa smoothSizes(), pointSizes()
1926 */
standardSizes()1927 QList<int> QFontDatabase::standardSizes()
1928 {
1929 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->standardSizes();
1930 }
1931
1932
1933 /*!
1934 Returns \c true if the font that has family \a family and style \a
1935 style is italic; otherwise returns \c false.
1936
1937 \sa weight(), bold()
1938 */
italic(const QString & family,const QString & style) const1939 bool QFontDatabase::italic(const QString &family, const QString &style) const
1940 {
1941 QString familyName, foundryName;
1942 parseFontName(family, foundryName, familyName);
1943
1944 QMutexLocker locker(fontDatabaseMutex());
1945
1946 QT_PREPEND_NAMESPACE(load)(familyName);
1947
1948 QtFontFoundry allStyles(foundryName);
1949 QtFontFamily *f = d->family(familyName);
1950 if (!f) return false;
1951
1952 for (int j = 0; j < f->count; j++) {
1953 QtFontFoundry *foundry = f->foundries[j];
1954 if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1955 for (int k = 0; k < foundry->count; k++)
1956 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1957 }
1958 }
1959
1960 QtFontStyle::Key styleKey(style);
1961 QtFontStyle *s = allStyles.style(styleKey, style);
1962 return s && s->key.style == QFont::StyleItalic;
1963 }
1964
1965
1966 /*!
1967 Returns \c true if the font that has family \a family and style \a
1968 style is bold; otherwise returns \c false.
1969
1970 \sa italic(), weight()
1971 */
bold(const QString & family,const QString & style) const1972 bool QFontDatabase::bold(const QString &family,
1973 const QString &style) const
1974 {
1975 QString familyName, foundryName;
1976 parseFontName(family, foundryName, familyName);
1977
1978 QMutexLocker locker(fontDatabaseMutex());
1979
1980 QT_PREPEND_NAMESPACE(load)(familyName);
1981
1982 QtFontFoundry allStyles(foundryName);
1983 QtFontFamily *f = d->family(familyName);
1984 if (!f) return false;
1985
1986 for (int j = 0; j < f->count; j++) {
1987 QtFontFoundry *foundry = f->foundries[j];
1988 if (foundryName.isEmpty() ||
1989 foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
1990 for (int k = 0; k < foundry->count; k++)
1991 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
1992 }
1993 }
1994
1995 QtFontStyle::Key styleKey(style);
1996 QtFontStyle *s = allStyles.style(styleKey, style);
1997 return s && s->key.weight >= QFont::Bold;
1998 }
1999
2000
2001 /*!
2002 Returns the weight of the font that has family \a family and style
2003 \a style. If there is no such family and style combination,
2004 returns -1.
2005
2006 \sa italic(), bold()
2007 */
weight(const QString & family,const QString & style) const2008 int QFontDatabase::weight(const QString &family,
2009 const QString &style) const
2010 {
2011 QString familyName, foundryName;
2012 parseFontName(family, foundryName, familyName);
2013
2014 QMutexLocker locker(fontDatabaseMutex());
2015
2016 QT_PREPEND_NAMESPACE(load)(familyName);
2017
2018 QtFontFoundry allStyles(foundryName);
2019 QtFontFamily *f = d->family(familyName);
2020 if (!f) return -1;
2021
2022 for (int j = 0; j < f->count; j++) {
2023 QtFontFoundry *foundry = f->foundries[j];
2024 if (foundryName.isEmpty() ||
2025 foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
2026 for (int k = 0; k < foundry->count; k++)
2027 allStyles.style(foundry->styles[k]->key, foundry->styles[k]->styleName, true);
2028 }
2029 }
2030
2031 QtFontStyle::Key styleKey(style);
2032 QtFontStyle *s = allStyles.style(styleKey, style);
2033 return s ? s->key.weight : -1;
2034 }
2035
2036
2037 /*! \internal */
hasFamily(const QString & family) const2038 bool QFontDatabase::hasFamily(const QString &family) const
2039 {
2040 QString parsedFamily, foundry;
2041 parseFontName(family, foundry, parsedFamily);
2042 const QString familyAlias = resolveFontFamilyAlias(parsedFamily);
2043 return families().contains(familyAlias, Qt::CaseInsensitive);
2044 }
2045
2046
2047 /*!
2048 \since 5.5
2049
2050 Returns \c true if and only if the \a family font family is private.
2051
2052 This happens, for instance, on \macos and iOS, where the system UI fonts are not
2053 accessible to the user. For completeness, QFontDatabase::families() returns all
2054 font families, including the private ones. You should use this function if you
2055 are developing a font selection control in order to keep private fonts hidden.
2056
2057 \sa families()
2058 */
isPrivateFamily(const QString & family) const2059 bool QFontDatabase::isPrivateFamily(const QString &family) const
2060 {
2061 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->isPrivateFontFamily(family);
2062 }
2063
2064
2065 /*!
2066 Returns the names the \a writingSystem (e.g. for displaying to the
2067 user in a dialog).
2068 */
writingSystemName(WritingSystem writingSystem)2069 QString QFontDatabase::writingSystemName(WritingSystem writingSystem)
2070 {
2071 const char *name = nullptr;
2072 switch (writingSystem) {
2073 case Any:
2074 name = QT_TRANSLATE_NOOP("QFontDatabase", "Any");
2075 break;
2076 case Latin:
2077 name = QT_TRANSLATE_NOOP("QFontDatabase", "Latin");
2078 break;
2079 case Greek:
2080 name = QT_TRANSLATE_NOOP("QFontDatabase", "Greek");
2081 break;
2082 case Cyrillic:
2083 name = QT_TRANSLATE_NOOP("QFontDatabase", "Cyrillic");
2084 break;
2085 case Armenian:
2086 name = QT_TRANSLATE_NOOP("QFontDatabase", "Armenian");
2087 break;
2088 case Hebrew:
2089 name = QT_TRANSLATE_NOOP("QFontDatabase", "Hebrew");
2090 break;
2091 case Arabic:
2092 name = QT_TRANSLATE_NOOP("QFontDatabase", "Arabic");
2093 break;
2094 case Syriac:
2095 name = QT_TRANSLATE_NOOP("QFontDatabase", "Syriac");
2096 break;
2097 case Thaana:
2098 name = QT_TRANSLATE_NOOP("QFontDatabase", "Thaana");
2099 break;
2100 case Devanagari:
2101 name = QT_TRANSLATE_NOOP("QFontDatabase", "Devanagari");
2102 break;
2103 case Bengali:
2104 name = QT_TRANSLATE_NOOP("QFontDatabase", "Bengali");
2105 break;
2106 case Gurmukhi:
2107 name = QT_TRANSLATE_NOOP("QFontDatabase", "Gurmukhi");
2108 break;
2109 case Gujarati:
2110 name = QT_TRANSLATE_NOOP("QFontDatabase", "Gujarati");
2111 break;
2112 case Oriya:
2113 name = QT_TRANSLATE_NOOP("QFontDatabase", "Oriya");
2114 break;
2115 case Tamil:
2116 name = QT_TRANSLATE_NOOP("QFontDatabase", "Tamil");
2117 break;
2118 case Telugu:
2119 name = QT_TRANSLATE_NOOP("QFontDatabase", "Telugu");
2120 break;
2121 case Kannada:
2122 name = QT_TRANSLATE_NOOP("QFontDatabase", "Kannada");
2123 break;
2124 case Malayalam:
2125 name = QT_TRANSLATE_NOOP("QFontDatabase", "Malayalam");
2126 break;
2127 case Sinhala:
2128 name = QT_TRANSLATE_NOOP("QFontDatabase", "Sinhala");
2129 break;
2130 case Thai:
2131 name = QT_TRANSLATE_NOOP("QFontDatabase", "Thai");
2132 break;
2133 case Lao:
2134 name = QT_TRANSLATE_NOOP("QFontDatabase", "Lao");
2135 break;
2136 case Tibetan:
2137 name = QT_TRANSLATE_NOOP("QFontDatabase", "Tibetan");
2138 break;
2139 case Myanmar:
2140 name = QT_TRANSLATE_NOOP("QFontDatabase", "Myanmar");
2141 break;
2142 case Georgian:
2143 name = QT_TRANSLATE_NOOP("QFontDatabase", "Georgian");
2144 break;
2145 case Khmer:
2146 name = QT_TRANSLATE_NOOP("QFontDatabase", "Khmer");
2147 break;
2148 case SimplifiedChinese:
2149 name = QT_TRANSLATE_NOOP("QFontDatabase", "Simplified Chinese");
2150 break;
2151 case TraditionalChinese:
2152 name = QT_TRANSLATE_NOOP("QFontDatabase", "Traditional Chinese");
2153 break;
2154 case Japanese:
2155 name = QT_TRANSLATE_NOOP("QFontDatabase", "Japanese");
2156 break;
2157 case Korean:
2158 name = QT_TRANSLATE_NOOP("QFontDatabase", "Korean");
2159 break;
2160 case Vietnamese:
2161 name = QT_TRANSLATE_NOOP("QFontDatabase", "Vietnamese");
2162 break;
2163 case Symbol:
2164 name = QT_TRANSLATE_NOOP("QFontDatabase", "Symbol");
2165 break;
2166 case Ogham:
2167 name = QT_TRANSLATE_NOOP("QFontDatabase", "Ogham");
2168 break;
2169 case Runic:
2170 name = QT_TRANSLATE_NOOP("QFontDatabase", "Runic");
2171 break;
2172 case Nko:
2173 name = QT_TRANSLATE_NOOP("QFontDatabase", "N'Ko");
2174 break;
2175 default:
2176 Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter");
2177 break;
2178 }
2179 return QCoreApplication::translate("QFontDatabase", name);
2180 }
2181
2182
2183 /*!
2184 Returns a string with sample characters from \a writingSystem.
2185 */
writingSystemSample(WritingSystem writingSystem)2186 QString QFontDatabase::writingSystemSample(WritingSystem writingSystem)
2187 {
2188 QString sample;
2189 switch (writingSystem) {
2190 case Any:
2191 case Symbol:
2192 // show only ascii characters
2193 sample += QLatin1String("AaBbzZ");
2194 break;
2195 case Latin:
2196 // This is cheating... we only show latin-1 characters so that we don't
2197 // end up loading lots of fonts - at least on X11...
2198 sample = QLatin1String("Aa");
2199 sample += QChar(0x00C3);
2200 sample += QChar(0x00E1);
2201 sample += QLatin1String("Zz");
2202 break;
2203 case Greek:
2204 sample += QChar(0x0393);
2205 sample += QChar(0x03B1);
2206 sample += QChar(0x03A9);
2207 sample += QChar(0x03C9);
2208 break;
2209 case Cyrillic:
2210 sample += QChar(0x0414);
2211 sample += QChar(0x0434);
2212 sample += QChar(0x0436);
2213 sample += QChar(0x044f);
2214 break;
2215 case Armenian:
2216 sample += QChar(0x053f);
2217 sample += QChar(0x054f);
2218 sample += QChar(0x056f);
2219 sample += QChar(0x057f);
2220 break;
2221 case Hebrew:
2222 sample += QChar(0x05D0);
2223 sample += QChar(0x05D1);
2224 sample += QChar(0x05D2);
2225 sample += QChar(0x05D3);
2226 break;
2227 case Arabic:
2228 sample += QChar(0x0623);
2229 sample += QChar(0x0628);
2230 sample += QChar(0x062C);
2231 sample += QChar(0x062F);
2232 sample += QChar(0x064A);
2233 sample += QChar(0x0629);
2234 sample += QChar(0x0020);
2235 sample += QChar(0x0639);
2236 sample += QChar(0x0631);
2237 sample += QChar(0x0628);
2238 sample += QChar(0x064A);
2239 sample += QChar(0x0629);
2240 break;
2241 case Syriac:
2242 sample += QChar(0x0715);
2243 sample += QChar(0x0725);
2244 sample += QChar(0x0716);
2245 sample += QChar(0x0726);
2246 break;
2247 case Thaana:
2248 sample += QChar(0x0784);
2249 sample += QChar(0x0794);
2250 sample += QChar(0x078c);
2251 sample += QChar(0x078d);
2252 break;
2253 case Devanagari:
2254 sample += QChar(0x0905);
2255 sample += QChar(0x0915);
2256 sample += QChar(0x0925);
2257 sample += QChar(0x0935);
2258 break;
2259 case Bengali:
2260 sample += QChar(0x0986);
2261 sample += QChar(0x0996);
2262 sample += QChar(0x09a6);
2263 sample += QChar(0x09b6);
2264 break;
2265 case Gurmukhi:
2266 sample += QChar(0x0a05);
2267 sample += QChar(0x0a15);
2268 sample += QChar(0x0a25);
2269 sample += QChar(0x0a35);
2270 break;
2271 case Gujarati:
2272 sample += QChar(0x0a85);
2273 sample += QChar(0x0a95);
2274 sample += QChar(0x0aa5);
2275 sample += QChar(0x0ab5);
2276 break;
2277 case Oriya:
2278 sample += QChar(0x0b06);
2279 sample += QChar(0x0b16);
2280 sample += QChar(0x0b2b);
2281 sample += QChar(0x0b36);
2282 break;
2283 case Tamil:
2284 sample += QChar(0x0b89);
2285 sample += QChar(0x0b99);
2286 sample += QChar(0x0ba9);
2287 sample += QChar(0x0bb9);
2288 break;
2289 case Telugu:
2290 sample += QChar(0x0c05);
2291 sample += QChar(0x0c15);
2292 sample += QChar(0x0c25);
2293 sample += QChar(0x0c35);
2294 break;
2295 case Kannada:
2296 sample += QChar(0x0c85);
2297 sample += QChar(0x0c95);
2298 sample += QChar(0x0ca5);
2299 sample += QChar(0x0cb5);
2300 break;
2301 case Malayalam:
2302 sample += QChar(0x0d05);
2303 sample += QChar(0x0d15);
2304 sample += QChar(0x0d25);
2305 sample += QChar(0x0d35);
2306 break;
2307 case Sinhala:
2308 sample += QChar(0x0d90);
2309 sample += QChar(0x0da0);
2310 sample += QChar(0x0db0);
2311 sample += QChar(0x0dc0);
2312 break;
2313 case Thai:
2314 sample += QChar(0x0e02);
2315 sample += QChar(0x0e12);
2316 sample += QChar(0x0e22);
2317 sample += QChar(0x0e32);
2318 break;
2319 case Lao:
2320 sample += QChar(0x0e8d);
2321 sample += QChar(0x0e9d);
2322 sample += QChar(0x0ead);
2323 sample += QChar(0x0ebd);
2324 break;
2325 case Tibetan:
2326 sample += QChar(0x0f00);
2327 sample += QChar(0x0f01);
2328 sample += QChar(0x0f02);
2329 sample += QChar(0x0f03);
2330 break;
2331 case Myanmar:
2332 sample += QChar(0x1000);
2333 sample += QChar(0x1001);
2334 sample += QChar(0x1002);
2335 sample += QChar(0x1003);
2336 break;
2337 case Georgian:
2338 sample += QChar(0x10a0);
2339 sample += QChar(0x10b0);
2340 sample += QChar(0x10c0);
2341 sample += QChar(0x10d0);
2342 break;
2343 case Khmer:
2344 sample += QChar(0x1780);
2345 sample += QChar(0x1790);
2346 sample += QChar(0x17b0);
2347 sample += QChar(0x17c0);
2348 break;
2349 case SimplifiedChinese:
2350 sample += QChar(0x4e2d);
2351 sample += QChar(0x6587);
2352 sample += QChar(0x8303);
2353 sample += QChar(0x4f8b);
2354 break;
2355 case TraditionalChinese:
2356 sample += QChar(0x4e2d);
2357 sample += QChar(0x6587);
2358 sample += QChar(0x7bc4);
2359 sample += QChar(0x4f8b);
2360 break;
2361 case Japanese:
2362 sample += QChar(0x30b5);
2363 sample += QChar(0x30f3);
2364 sample += QChar(0x30d7);
2365 sample += QChar(0x30eb);
2366 sample += QChar(0x3067);
2367 sample += QChar(0x3059);
2368 break;
2369 case Korean:
2370 sample += QChar(0xac00);
2371 sample += QChar(0xac11);
2372 sample += QChar(0xac1a);
2373 sample += QChar(0xac2f);
2374 break;
2375 case Vietnamese:
2376 {
2377 static const char vietnameseUtf8[] = {
2378 char(0xef), char(0xbb), char(0xbf), char(0xe1), char(0xbb), char(0x97),
2379 char(0xe1), char(0xbb), char(0x99),
2380 char(0xe1), char(0xbb), char(0x91),
2381 char(0xe1), char(0xbb), char(0x93),
2382 };
2383 sample += QString::fromUtf8(vietnameseUtf8, sizeof(vietnameseUtf8));
2384 break;
2385 }
2386 case Ogham:
2387 sample += QChar(0x1681);
2388 sample += QChar(0x1682);
2389 sample += QChar(0x1683);
2390 sample += QChar(0x1684);
2391 break;
2392 case Runic:
2393 sample += QChar(0x16a0);
2394 sample += QChar(0x16a1);
2395 sample += QChar(0x16a2);
2396 sample += QChar(0x16a3);
2397 break;
2398 case Nko:
2399 sample += QChar(0x7ca);
2400 sample += QChar(0x7cb);
2401 sample += QChar(0x7cc);
2402 sample += QChar(0x7cd);
2403 break;
2404 default:
2405 break;
2406 }
2407 return sample;
2408 }
2409
2410
parseFontName(const QString & name,QString & foundry,QString & family)2411 void QFontDatabase::parseFontName(const QString &name, QString &foundry, QString &family)
2412 {
2413 QT_PREPEND_NAMESPACE(parseFontName)(name, foundry, family);
2414 }
2415
createDatabase()2416 void QFontDatabase::createDatabase()
2417 { initializeDb(); }
2418
2419 // used from qfontengine_ft.cpp
qt_fontdata_from_index(int index)2420 Q_GUI_EXPORT QByteArray qt_fontdata_from_index(int index)
2421 {
2422 QMutexLocker locker(fontDatabaseMutex());
2423 return privateDb()->applicationFonts.value(index).data;
2424 }
2425
addAppFont(const QByteArray & fontData,const QString & fileName)2426 int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &fileName)
2427 {
2428 QFontDatabasePrivate::ApplicationFont font;
2429 font.data = fontData;
2430 font.fileName = fileName;
2431
2432 Q_TRACE(QFontDatabasePrivate_addAppFont, fileName);
2433
2434 int i;
2435 for (i = 0; i < applicationFonts.count(); ++i)
2436 if (applicationFonts.at(i).families.isEmpty())
2437 break;
2438 if (i >= applicationFonts.count()) {
2439 applicationFonts.append(ApplicationFont());
2440 i = applicationFonts.count() - 1;
2441 }
2442
2443 if (font.fileName.isEmpty() && !fontData.isEmpty())
2444 font.fileName = QLatin1String(":qmemoryfonts/") + QString::number(i);
2445
2446 bool wasEmpty = privateDb()->count == 0;
2447 registerFont(&font);
2448 if (font.families.isEmpty())
2449 return -1;
2450
2451 applicationFonts[i] = font;
2452
2453 // If the cache has not yet been populated, we need to reload the application font later
2454 if (wasEmpty)
2455 invalidate();
2456 else
2457 emit qApp->fontDatabaseChanged();
2458 return i;
2459 }
2460
isApplicationFont(const QString & fileName)2461 bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
2462 {
2463 for (int i = 0; i < applicationFonts.count(); ++i)
2464 if (applicationFonts.at(i).fileName == fileName)
2465 return true;
2466 return false;
2467 }
2468
2469 /*!
2470 \since 4.2
2471
2472 Loads the font from the file specified by \a fileName and makes it available to
2473 the application. An ID is returned that can be used to remove the font again
2474 with removeApplicationFont() or to retrieve the list of family names contained
2475 in the font.
2476
2477 The function returns -1 if the font could not be loaded.
2478
2479 Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
2480 supported.
2481
2482 \note Adding application fonts on Unix/X11 platforms without fontconfig is
2483 currently not supported.
2484
2485 \sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
2486 */
addApplicationFont(const QString & fileName)2487 int QFontDatabase::addApplicationFont(const QString &fileName)
2488 {
2489 QByteArray data;
2490 if (!QFileInfo(fileName).isNativePath()) {
2491 QFile f(fileName);
2492 if (!f.open(QIODevice::ReadOnly))
2493 return -1;
2494
2495 Q_TRACE(QFontDatabase_addApplicationFont, fileName);
2496
2497 data = f.readAll();
2498 }
2499 QMutexLocker locker(fontDatabaseMutex());
2500 return privateDb()->addAppFont(data, fileName);
2501 }
2502
2503 /*!
2504 \since 4.2
2505
2506 Loads the font from binary data specified by \a fontData and makes it available to
2507 the application. An ID is returned that can be used to remove the font again
2508 with removeApplicationFont() or to retrieve the list of family names contained
2509 in the font.
2510
2511 The function returns -1 if the font could not be loaded.
2512
2513 Currently only TrueType fonts and TrueType font collections are supported.
2514
2515 \b{Note:} Adding application fonts on Unix/X11 platforms without fontconfig is
2516 currently not supported.
2517
2518 \sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
2519 */
addApplicationFontFromData(const QByteArray & fontData)2520 int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData)
2521 {
2522 QMutexLocker locker(fontDatabaseMutex());
2523 return privateDb()->addAppFont(fontData, QString() /* fileName */);
2524 }
2525
2526 /*!
2527 \since 4.2
2528
2529 Returns a list of font families for the given application font identified by
2530 \a id.
2531
2532 \sa addApplicationFont(), addApplicationFontFromData()
2533 */
applicationFontFamilies(int id)2534 QStringList QFontDatabase::applicationFontFamilies(int id)
2535 {
2536 QMutexLocker locker(fontDatabaseMutex());
2537 return privateDb()->applicationFonts.value(id).families;
2538 }
2539
2540 /*!
2541 \since 5.2
2542
2543 Returns the most adequate font for a given \a type case for proper integration
2544 with the system's look and feel.
2545
2546 \sa QGuiApplication::font()
2547 */
2548
systemFont(QFontDatabase::SystemFont type)2549 QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type)
2550 {
2551 const QFont *font = nullptr;
2552 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
2553 switch (type) {
2554 case GeneralFont:
2555 font = theme->font(QPlatformTheme::SystemFont);
2556 break;
2557 case FixedFont:
2558 font = theme->font(QPlatformTheme::FixedFont);
2559 break;
2560 case TitleFont:
2561 font = theme->font(QPlatformTheme::TitleBarFont);
2562 break;
2563 case SmallestReadableFont:
2564 font = theme->font(QPlatformTheme::MiniFont);
2565 break;
2566 }
2567 }
2568
2569 if (font)
2570 return *font;
2571 else if (QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration())
2572 return integration->fontDatabase()->defaultFont();
2573 else
2574 return QFont();
2575 }
2576
2577 /*!
2578 \fn bool QFontDatabase::removeApplicationFont(int id)
2579 \since 4.2
2580
2581 Removes the previously loaded application font identified by \a
2582 id. Returns \c true if unloading of the font succeeded; otherwise
2583 returns \c false.
2584
2585 \sa removeAllApplicationFonts(), addApplicationFont(),
2586 addApplicationFontFromData()
2587 */
removeApplicationFont(int handle)2588 bool QFontDatabase::removeApplicationFont(int handle)
2589 {
2590 QMutexLocker locker(fontDatabaseMutex());
2591
2592 QFontDatabasePrivate *db = privateDb();
2593 if (handle < 0 || handle >= db->applicationFonts.count())
2594 return false;
2595
2596 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
2597
2598 db->invalidate();
2599 return true;
2600 }
2601
2602 /*!
2603 \fn bool QFontDatabase::removeAllApplicationFonts()
2604 \since 4.2
2605
2606 Removes all application-local fonts previously added using addApplicationFont()
2607 and addApplicationFontFromData().
2608
2609 Returns \c true if unloading of the fonts succeeded; otherwise
2610 returns \c false.
2611
2612 \sa removeApplicationFont(), addApplicationFont(), addApplicationFontFromData()
2613 */
removeAllApplicationFonts()2614 bool QFontDatabase::removeAllApplicationFonts()
2615 {
2616 QMutexLocker locker(fontDatabaseMutex());
2617
2618 QFontDatabasePrivate *db = privateDb();
2619 if (!db || db->applicationFonts.isEmpty())
2620 return false;
2621
2622 db->applicationFonts.clear();
2623 db->invalidate();
2624 return true;
2625 }
2626
2627 /*!
2628 \fn bool QFontDatabase::supportsThreadedFontRendering()
2629 \since 4.4
2630 \deprecated
2631
2632 Returns \c true if font rendering is supported outside the GUI
2633 thread, false otherwise. In other words, a return value of false
2634 means that all QPainter::drawText() calls outside the GUI thread
2635 will not produce readable output.
2636
2637 As of 5.0, always returns \c true.
2638
2639 \sa {Thread-Support in Qt Modules#Painting In Threads}{Painting In Threads}
2640 */
2641 #if QT_DEPRECATED_SINCE(5, 2)
supportsThreadedFontRendering()2642 bool QFontDatabase::supportsThreadedFontRendering()
2643 {
2644 return true;
2645 }
2646 #endif
2647
2648 /*!
2649 \internal
2650 */
findFont(const QFontDef & request,int script)2651 QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
2652 {
2653 QMutexLocker locker(fontDatabaseMutex());
2654
2655 if (!privateDb()->count)
2656 initializeDb();
2657
2658 QFontEngine *engine;
2659
2660 #if defined(QT_BUILD_INTERNAL)
2661 // For testing purpose only, emulates an exact-matching monospace font
2662 if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
2663 engine = new QTestFontEngine(request.pixelSize);
2664 engine->fontDef = request;
2665 return engine;
2666 }
2667 #endif
2668
2669 QFontCache *fontCache = QFontCache::instance();
2670
2671 // Until we specifically asked not to, try looking for Multi font engine
2672 // first, the last '1' indicates that we want Multi font engine instead
2673 // of single ones
2674 bool multi = !(request.styleStrategy & QFont::NoFontMerging);
2675 QFontCache::Key key(request, script, multi ? 1 : 0);
2676 engine = fontCache->findEngine(key);
2677 if (engine) {
2678 qCDebug(lcFontMatch, "Cache hit level 1");
2679 return engine;
2680 }
2681
2682 if (request.pixelSize > 0xffff) {
2683 // Stop absurd requests reaching the engines; pixel size is assumed to fit ushort
2684 qCDebug(lcFontMatch, "Rejecting request for pixel size %g2, returning box engine", double(request.pixelSize));
2685 return new QFontEngineBox(32); // not request.pixelSize, to avoid overflow/DOS
2686 }
2687
2688 QString family_name, foundry_name;
2689 const QString requestFamily = request.families.size() > 0 ? request.families.at(0) : request.family;
2690 parseFontName(requestFamily, foundry_name, family_name);
2691 QtFontDesc desc;
2692 QList<int> blackListed;
2693 int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
2694 if (index < 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
2695 // We populated familiy aliases (e.g. localized families), so try again
2696 index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
2697 }
2698 if (index >= 0) {
2699 QFontDef fontDef = request;
2700
2701 // Don't pass empty family names to the platform font database, since it will then invoke its own matching
2702 // and we will be out of sync with the matched font.
2703 if (fontDef.families.isEmpty() && fontDef.family.isEmpty())
2704 fontDef.families = QStringList(desc.family->name);
2705
2706 engine = loadEngine(script, fontDef, desc.family, desc.foundry, desc.style, desc.size);
2707
2708 if (engine)
2709 initFontDef(desc, request, &engine->fontDef, multi);
2710 else
2711 blackListed.append(index);
2712 } else {
2713 qCDebug(lcFontMatch, " NO MATCH FOUND\n");
2714 }
2715
2716 if (!engine) {
2717 if (!requestFamily.isEmpty()) {
2718 QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
2719 if (styleHint == QFont::AnyStyle && request.fixedPitch)
2720 styleHint = QFont::TypeWriter;
2721
2722 QStringList fallbacks = request.fallBackFamilies
2723 + fallbacksForFamily(requestFamily,
2724 QFont::Style(request.style),
2725 styleHint,
2726 QChar::Script(script));
2727 if (script > QChar::Script_Common)
2728 fallbacks += QString(); // Find the first font matching the specified script.
2729
2730 for (int i = 0; !engine && i < fallbacks.size(); i++) {
2731 QFontDef def = request;
2732 def.families.clear();
2733 def.family = fallbacks.at(i);
2734 QFontCache::Key key(def, script, multi ? 1 : 0);
2735 engine = fontCache->findEngine(key);
2736 if (!engine) {
2737 QtFontDesc desc;
2738 do {
2739 index = match(multi ? QChar::Script_Common : script, def, def.family, QLatin1String(""), &desc, blackListed);
2740 if (index >= 0) {
2741 QFontDef loadDef = def;
2742 if (loadDef.families.isEmpty() && loadDef.family.isEmpty())
2743 loadDef.family = desc.family->name;
2744 engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size);
2745 if (engine)
2746 initFontDef(desc, loadDef, &engine->fontDef, multi);
2747 else
2748 blackListed.append(index);
2749 }
2750 } while (index >= 0 && !engine);
2751 }
2752 }
2753 }
2754
2755 if (!engine)
2756 engine = new QFontEngineBox(request.pixelSize);
2757
2758 qCDebug(lcFontMatch, "returning box engine");
2759 }
2760
2761 return engine;
2762 }
2763
load(const QFontPrivate * d,int script)2764 void QFontDatabase::load(const QFontPrivate *d, int script)
2765 {
2766 QFontDef req = d->request;
2767
2768 if (req.pixelSize == -1) {
2769 req.pixelSize = std::floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100;
2770 req.pixelSize = qRound(req.pixelSize);
2771 }
2772 if (req.pointSize < 0)
2773 req.pointSize = req.pixelSize*72.0/d->dpi;
2774
2775 // respect the fallback families that might be passed through the request
2776 const QStringList fallBackFamilies = familyList(req);
2777
2778 if (!d->engineData) {
2779 QFontCache *fontCache = QFontCache::instance();
2780 // look for the requested font in the engine data cache
2781 // note: fallBackFamilies are not respected in the EngineData cache key;
2782 // join them with the primary selection family to avoid cache misses
2783 if (!d->request.family.isEmpty())
2784 req.family = fallBackFamilies.join(QLatin1Char(','));
2785 if (!d->request.families.isEmpty())
2786 req.families = fallBackFamilies;
2787
2788 d->engineData = fontCache->findEngineData(req);
2789 if (!d->engineData) {
2790 // create a new one
2791 d->engineData = new QFontEngineData;
2792 fontCache->insertEngineData(req, d->engineData);
2793 }
2794 d->engineData->ref.ref();
2795 }
2796
2797 // the cached engineData could have already loaded the engine we want
2798 if (d->engineData->engines[script])
2799 return;
2800
2801 QFontEngine *fe = nullptr;
2802
2803 Q_TRACE(QFontDatabase_load, req.family, req.pointSize);
2804
2805 req.fallBackFamilies = fallBackFamilies;
2806 if (!req.fallBackFamilies.isEmpty())
2807 req.families = QStringList(req.fallBackFamilies.takeFirst());
2808
2809 // list of families to try
2810 QStringList family_list;
2811
2812 if (!req.families.isEmpty()) {
2813 // Add primary selection
2814 family_list << req.families.at(0);
2815
2816 // add the default family
2817 QString defaultFamily = QGuiApplication::font().family();
2818 if (! family_list.contains(defaultFamily))
2819 family_list << defaultFamily;
2820
2821 }
2822
2823 // null family means find the first font matching the specified script
2824 family_list << QString();
2825
2826 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
2827 for (; !fe && it != end; ++it) {
2828 req.families = QStringList(*it);
2829
2830 fe = QFontDatabase::findFont(req, script);
2831 if (fe) {
2832 if (fe->type() == QFontEngine::Box && !req.families.at(0).isEmpty()) {
2833 if (fe->ref.loadRelaxed() == 0)
2834 delete fe;
2835 fe = nullptr;
2836 } else {
2837 if (d->dpi > 0)
2838 fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / d->dpi));
2839 }
2840 }
2841
2842 // No need to check requested fallback families again
2843 req.fallBackFamilies.clear();
2844 }
2845
2846 Q_ASSERT(fe);
2847 if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
2848 for (int i = 0; i < QChar::ScriptCount; ++i) {
2849 if (!d->engineData->engines[i]) {
2850 d->engineData->engines[i] = fe;
2851 fe->ref.ref();
2852 }
2853 }
2854 } else {
2855 d->engineData->engines[script] = fe;
2856 fe->ref.ref();
2857 }
2858 }
2859
resolveFontFamilyAlias(const QString & family)2860 QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
2861 {
2862 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
2863 }
2864
qt_sort_families_by_writing_system(QChar::Script script,const QStringList & families)2865 Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script, const QStringList &families)
2866 {
2867 size_t writingSystem = std::find(scriptForWritingSystem,
2868 scriptForWritingSystem + QFontDatabase::WritingSystemsCount,
2869 script) - scriptForWritingSystem;
2870 if (writingSystem == QFontDatabase::Any
2871 || writingSystem >= QFontDatabase::WritingSystemsCount) {
2872 return families;
2873 }
2874
2875 QFontDatabasePrivate *db = privateDb();
2876 QMultiMap<uint, QString> supported;
2877 for (int i = 0; i < families.size(); ++i) {
2878 const QString &family = families.at(i);
2879
2880 QtFontFamily *testFamily = nullptr;
2881 for (int x = 0; x < db->count; ++x) {
2882 if (Q_UNLIKELY(matchFamilyName(family, db->families[x]))) {
2883 testFamily = db->families[x];
2884 testFamily->ensurePopulated();
2885 break;
2886 }
2887 }
2888
2889 uint order = i;
2890 if (testFamily == nullptr
2891 || (testFamily->writingSystems[writingSystem] & QtFontFamily::Supported) == 0) {
2892 order |= 1u << 31;
2893 }
2894
2895 supported.insert(order, family);
2896 }
2897
2898 return supported.values();
2899 }
2900
2901 QT_END_NAMESPACE
2902
2903