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