21#include <private/qfontengine_p.h>
22#include <private/qpainter_p.h>
23#include <private/qtextengine_p.h>
26#include <qpa/qplatformscreen.h>
27#include <qpa/qplatformintegration.h>
28#include <qpa/qplatformfontdatabase.h>
29#include <QtGui/private/qguiapplication_p.h>
31#include <QtCore/QMutexLocker>
32#include <QtCore/QMutex>
37#ifdef QFONTCACHE_DEBUG
38# define FC_DEBUG qDebug
40# define FC_DEBUG if (false) qDebug
45#ifndef QFONTCACHE_DECREASE_TRIGGER_LIMIT
46# define QFONTCACHE_DECREASE_TRIGGER_LIMIT 256
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 if (pixelSize != -1 && other.pixelSize != -1) {
70 if (pixelSize != other.pixelSize)
72 }
else if (pointSize != -1 && other.pointSize != -1) {
73 if (pointSize != other.pointSize)
85 if (families.size() != other.families.size())
88 QString this_family, this_foundry, other_family, other_foundry;
89 for (
int i = 0; i < families.size(); ++i) {
90 QFontDatabasePrivate::parseFontName(families.at(i), this_foundry, this_family);
91 QFontDatabasePrivate::parseFontName(other.families.at(i), other_foundry, other_family);
92 if (this_family != other_family || this_foundry != other_foundry)
96 if (variableAxisValues != other.variableAxisValues)
99 return (styleHint == other.styleHint
100 && styleStrategy == other.styleStrategy
101 && weight == other.weight
102 && style == other.style
103 && this_family == other_family
104 && (styleName.isEmpty() || other.styleName.isEmpty() || styleName == other.styleName)
105 && (this_foundry.isEmpty()
106 || other_foundry.isEmpty()
107 || this_foundry == other_foundry)
115 if (QCoreApplication::instance()->testAttribute(Qt::AA_Use96Dpi))
121 if (
const QScreen *screen = QGuiApplication::primaryScreen())
122 return qRound(screen->logicalDotsPerInchX());
130 if (QCoreApplication::instance()->testAttribute(Qt::AA_Use96Dpi))
136 if (
const QScreen *screen = QGuiApplication::primaryScreen())
137 return qRound(screen->logicalDotsPerInchY());
145 return qt_defaultDpiY();
151 static constexpr std::array<
int, 2> legacyToOpenTypeMap[] = {
152 { 0, QFont::Thin }, { 12, QFont::ExtraLight }, { 25, QFont::Light },
153 { 50, QFont::Normal }, { 57, QFont::Medium }, { 63, QFont::DemiBold },
154 { 75, QFont::Bold }, { 81, QFont::ExtraBold }, { 87, QFont::Black },
157 int closestDist = INT_MAX;
161 for (
auto mapping : legacyToOpenTypeMap) {
162 const int weightOld = mapping[ inverted];
163 const int weightNew = mapping[!inverted];
164 const int dist = qAbs(weightOld - weight);
165 if (dist < closestDist) {
180 QStringList familyList;
181 if (family.isEmpty())
183 const auto list = QStringView{family}.split(u',');
184 const int numFamilies = list.size();
185 familyList.reserve(numFamilies);
186 for (
int i = 0; i < numFamilies; ++i) {
187 auto str = list.at(i).trimmed();
188 if ((str.startsWith(u'"') && str.endsWith(u'"'))
189 || (str.startsWith(u'\'') && str.endsWith(u'\''))) {
190 str = str.mid(1, str.size() - 2);
192 familyList << str.toString();
209QFontPrivate::QFontPrivate()
210 : engineData(
nullptr), dpi(qt_defaultDpi()),
211 underline(
false), overline(
false), strikeOut(
false), kerning(
true),
212 capital(0), letterSpacingIsAbsolute(
false), scFont(
nullptr)
216QFontPrivate::QFontPrivate(
const QFontPrivate &other)
217 : request(other.request), engineData(
nullptr), dpi(other.dpi),
218 underline(other.underline), overline(other.overline),
219 strikeOut(other.strikeOut), kerning(other.kerning),
220 capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
221 letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
222 features(other.features), scFont(other.scFont)
224 if (scFont && scFont !=
this)
228QFontPrivate::~QFontPrivate()
230 if (engineData && !engineData->ref.deref())
232 engineData =
nullptr;
233 if (scFont && scFont !=
this) {
234 if (!scFont->ref.deref())
242#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script]
244QFontEngine *QFontPrivate::engineForScript(
int script)
const
246 QMutexLocker locker(qt_fontdatabase_mutex());
247 if (script <= QChar::Script_Latin)
248 script = QChar::Script_Common;
249 if (engineData && engineData->fontCacheId != QFontCache::instance()->id()) {
251 if (!engineData->ref.deref())
253 engineData =
nullptr;
256 QFontDatabasePrivate::load(
this, script);
260QFontEngine *QFontPrivate::engineForCharacter(
char32_t c, EngineQueryOptions opt)
const
262 const bool smallCaps = !(opt & EngineQueryOption::IgnoreSmallCapsEngine);
263 const auto script = QChar::script(c);
265 if (smallCaps && capital == QFont::SmallCaps && QChar::isLower(c))
266 engine = smallCapsFontPrivate()->engineForScript(script);
268 engine = engineForScript(script);
269 Q_ASSERT(engine !=
nullptr);
273void QFontPrivate::alterCharForCapitalization(QChar &c)
const {
275 case QFont::AllUppercase:
276 case QFont::SmallCaps:
279 case QFont::AllLowercase:
282 case QFont::MixedCase:
287QFontPrivate *QFontPrivate::smallCapsFontPrivate()
const
291 QFont font(
const_cast<QFontPrivate *>(
this));
292 qreal pointSize = font.pointSizeF();
294 font.setPointSizeF(pointSize * .7);
296 font.setPixelSize((font.pixelSize() * 7 + 5) / 10);
297 scFont = font.d.data();
304void QFontPrivate::resolve(uint mask,
const QFontPrivate *other)
306 Q_ASSERT(other !=
nullptr);
310 if ((mask & QFont::AllPropertiesResolved) == QFont::AllPropertiesResolved)
return;
313 if (!(mask & QFont::FamiliesResolved))
314 request.families = other->request.families;
316 if (! (mask & QFont::StyleNameResolved))
317 request.styleName = other->request.styleName;
319 if (! (mask & QFont::SizeResolved)) {
320 request.pointSize = other->request.pointSize;
321 request.pixelSize = other->request.pixelSize;
324 if (! (mask & QFont::StyleHintResolved))
325 request.styleHint = other->request.styleHint;
327 if (! (mask & QFont::StyleStrategyResolved))
328 request.styleStrategy = other->request.styleStrategy;
330 if (! (mask & QFont::WeightResolved))
331 request.weight = other->request.weight;
333 if (! (mask & QFont::StyleResolved))
334 request.style = other->request.style;
336 if (! (mask & QFont::FixedPitchResolved))
337 request.fixedPitch = other->request.fixedPitch;
339 if (! (mask & QFont::StretchResolved))
340 request.stretch = other->request.stretch;
342 if (! (mask & QFont::HintingPreferenceResolved))
343 request.hintingPreference = other->request.hintingPreference;
345 if (! (mask & QFont::UnderlineResolved))
346 underline = other->underline;
348 if (! (mask & QFont::OverlineResolved))
349 overline = other->overline;
351 if (! (mask & QFont::StrikeOutResolved))
352 strikeOut = other->strikeOut;
354 if (! (mask & QFont::KerningResolved))
355 kerning = other->kerning;
357 if (! (mask & QFont::LetterSpacingResolved)) {
358 letterSpacing = other->letterSpacing;
359 letterSpacingIsAbsolute = other->letterSpacingIsAbsolute;
361 if (! (mask & QFont::WordSpacingResolved))
362 wordSpacing = other->wordSpacing;
363 if (! (mask & QFont::CapitalizationResolved))
364 capital = other->capital;
366 if (!(mask & QFont::FeaturesResolved))
367 features = other->features;
369 if (!(mask & QFont::VariableAxesResolved))
370 request.variableAxisValues = other->request.variableAxisValues;
373bool QFontPrivate::hasVariableAxis(QFont::Tag tag,
float value)
const
375 return request.variableAxisValues.contains(tag) && request.variableAxisValues.value(tag) == value;
378void QFontPrivate::setVariableAxis(QFont::Tag tag,
float value)
380 request.variableAxisValues.insert(tag, value);
383void QFontPrivate::unsetVariableAxis(QFont::Tag tag)
385 request.variableAxisValues.remove(tag);
388void QFontPrivate::setFeature(QFont::Tag tag, quint32 value)
390 features.insert(tag, value);
393void QFontPrivate::unsetFeature(QFont::Tag tag)
395 features.remove(tag);
402 memset(engines, 0, QFontDatabasePrivate::ScriptCount *
sizeof(QFontEngine *));
407 Q_ASSERT(ref.loadRelaxed() == 0);
408 for (
int i = 0; i < QFontDatabasePrivate::ScriptCount; ++i) {
410 if (!engines[i]->ref.deref())
412 engines[i] =
nullptr;
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
610
611
612
613
614
615
616
617
618
619
620
621
622
623
626
627
628
629
630
631
634
635
636
637QFont::QFont(
const QFont &font,
const QPaintDevice *pd)
638 : resolve_mask(font.resolve_mask)
641 const int dpi = pd->logicalDpiY();
642 if (font.d->dpi != dpi) {
643 d =
new QFontPrivate(*font.d);
651
652
653QFont::QFont(QFontPrivate *data)
654 : d(data), resolve_mask(QFont::AllPropertiesResolved)
659
660
663 if (d->ref.loadRelaxed() == 1) {
664 if (d->engineData && !d->engineData->ref.deref())
665 delete d->engineData;
666 d->engineData =
nullptr;
667 if (d->scFont && d->scFont != d.data()) {
668 if (!d->scFont->ref.deref())
679
680
681
682
683
684void QFontPrivate::detachButKeepEngineData(QFont *font)
686 if (font->d->ref.loadRelaxed() == 1)
689 QFontEngineData *engineData = font->d->engineData;
691 engineData->ref.ref();
693 font->d->engineData = engineData;
697
698
699
700
702 : d(QGuiApplicationPrivate::instance() ? QGuiApplication::font().d.data() :
new QFontPrivate()), resolve_mask(0)
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728QFont::QFont(
const QString &family,
int pointSize,
int weight,
bool italic)
729 : d(
new QFontPrivate()), resolve_mask(QFont::FamiliesResolved)
731 if (pointSize <= 0) {
734 resolve_mask |= QFont::SizeResolved;
740 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
744 resolve_mask |= QFont::StyleResolved;
746 d->request.families = splitIntoFamilies(family);
747 d->request.pointSize = qreal(pointSize);
748 d->request.pixelSize = -1;
749 d->request.weight = weight;
750 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771QFont::QFont(
const QStringList &families,
int pointSize,
int weight,
bool italic)
772 : d(
new QFontPrivate()), resolve_mask(QFont::FamiliesResolved)
777 resolve_mask |= QFont::SizeResolved;
782 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
785 resolve_mask |= QFont::StyleResolved;
787 d->request.families = families;
788 d->request.pointSize = qreal(pointSize);
789 d->request.pixelSize = -1;
790 d->request.weight = weight;
791 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
795
796
797QFont::QFont(
const QFont &font)
798 : d(font.d), resolve_mask(font.resolve_mask)
803
804
810
811
812QFont &QFont::operator=(
const QFont &font)
815 resolve_mask = font.resolve_mask;
820
821
822
823
826
827
828
829
830
831QString QFont::family()
const
833 return d->request.families.isEmpty() ? QString() : d->request.families.constFirst();
837
838
839
840
841
842
843
844
845
846
847
848
849void QFont::setFamily(
const QString &family)
851 setFamilies(QStringList(family));
855
856
857
858
859
860
861
862
863QString QFont::styleName()
const
865 return d->request.styleName;
869
870
871
872
873
874
875
876
877
878
879
880
881void QFont::setStyleName(
const QString &styleName)
883 if ((resolve_mask & QFont::StyleNameResolved) && d->request.styleName == styleName)
888 d->request.styleName = styleName;
889 resolve_mask |= QFont::StyleNameResolved;
893
894
895
896
897
898int QFont::pointSize()
const
900 return qRound(d->request.pointSize);
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
962
963
964
965
966
967
968
969
970
971void QFont::setHintingPreference(HintingPreference hintingPreference)
973 if ((resolve_mask & QFont::HintingPreferenceResolved) && d->request.hintingPreference == hintingPreference)
978 d->request.hintingPreference = hintingPreference;
980 resolve_mask |= QFont::HintingPreferenceResolved;
984
985
986
987
988QFont::HintingPreference QFont::hintingPreference()
const
990 return QFont::HintingPreference(d->request.hintingPreference);
994
995
996
997
998
999void QFont::setPointSize(
int pointSize)
1001 if (pointSize <= 0) {
1002 qWarning(
"QFont::setPointSize: Point size <= 0 (%d), must be greater than 0", pointSize);
1006 if ((resolve_mask & QFont::SizeResolved) && d->request.pointSize == qreal(pointSize))
1011 d->request.pointSize = qreal(pointSize);
1012 d->request.pixelSize = -1;
1014 resolve_mask |= QFont::SizeResolved;
1018
1019
1020
1021
1022
1023
1024void QFont::setPointSizeF(qreal pointSize)
1026 if (pointSize <= 0) {
1027 qWarning(
"QFont::setPointSizeF: Point size <= 0 (%f), must be greater than 0", pointSize);
1031 if ((resolve_mask & QFont::SizeResolved) && d->request.pointSize == pointSize)
1036 d->request.pointSize = pointSize;
1037 d->request.pixelSize = -1;
1039 resolve_mask |= QFont::SizeResolved;
1043
1044
1045
1046
1047
1048qreal QFont::pointSizeF()
const
1050 return d->request.pointSize;
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063void QFont::setPixelSize(
int pixelSize)
1065 if (pixelSize <= 0) {
1066 qWarning(
"QFont::setPixelSize: Pixel size <= 0 (%d)", pixelSize);
1070 if ((resolve_mask & QFont::SizeResolved) && d->request.pixelSize == qreal(pixelSize))
1075 d->request.pixelSize = pixelSize;
1076 d->request.pointSize = -1;
1078 resolve_mask |= QFont::SizeResolved;
1082
1083
1084
1085
1086
1087
1088int QFont::pixelSize()
const
1090 return d->request.pixelSize;
1094
1095
1096
1097
1098
1099
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1115
1116
1117
1118
1119QFont::Style QFont::style()
const
1121 return (QFont::Style)d->request.style;
1126
1127
1128
1129
1130void QFont::setStyle(Style style)
1132 if ((resolve_mask & QFont::StyleResolved) && d->request.style == style)
1137 d->request.style = style;
1138 resolve_mask |= QFont::StyleResolved;
1142
1143
1144
1145
1146
1147QFont::Weight QFont::weight()
const
1149 return static_cast<Weight>(d->request.weight);
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1171#if QT_DEPRECATED_SINCE(6
, 0
)
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187void QFont::setLegacyWeight(
int legacyWeight)
1189 setWeight(QFont::Weight(qt_legacyToOpenTypeWeight(legacyWeight)));
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205int QFont::legacyWeight()
const
1207 return qt_openTypeToLegacyWeight(weight());
1212
1213
1214
1215
1216
1217
1218
1219void QFont::setWeight(QFont::Weight weight)
1222 if (weightValue !=
static_cast<
int>(weight)) {
1223 qWarning() <<
"QFont::setWeight: Weight must be between 1 and 1000, attempted to set "
1224 <<
static_cast<
int>(weight);
1227 if ((resolve_mask & QFont::WeightResolved) && d->request.weight == weightValue)
1232 d->request.weight = weightValue;
1233 resolve_mask |= QFont::WeightResolved;
1237
1238
1239
1240
1241
1242
1243
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1261
1262
1263
1264
1265bool QFont::underline()
const
1267 return d->underline;
1271
1272
1273
1274
1275
1276void QFont::setUnderline(
bool enable)
1278 if ((resolve_mask & QFont::UnderlineResolved) && d->underline == enable)
1281 QFontPrivate::detachButKeepEngineData(
this);
1283 d->underline = enable;
1284 resolve_mask |= QFont::UnderlineResolved;
1288
1289
1290
1291
1292bool QFont::overline()
const
1298
1299
1300
1301
1302void QFont::setOverline(
bool enable)
1304 if ((resolve_mask & QFont::OverlineResolved) && d->overline == enable)
1307 QFontPrivate::detachButKeepEngineData(
this);
1309 d->overline = enable;
1310 resolve_mask |= QFont::OverlineResolved;
1314
1315
1316
1317
1318bool QFont::strikeOut()
const
1320 return d->strikeOut;
1324
1325
1326
1327
1328
1329void QFont::setStrikeOut(
bool enable)
1331 if ((resolve_mask & QFont::StrikeOutResolved) && d->strikeOut == enable)
1334 QFontPrivate::detachButKeepEngineData(
this);
1336 d->strikeOut = enable;
1337 resolve_mask |= QFont::StrikeOutResolved;
1341
1342
1343
1344
1345bool QFont::fixedPitch()
const
1347 return d->request.fixedPitch;
1351
1352
1353
1354
1355
1356void QFont::setFixedPitch(
bool enable)
1358 if ((resolve_mask & QFont::FixedPitchResolved) && d->request.fixedPitch == enable)
1363 d->request.fixedPitch = enable;
1364 d->request.ignorePitch =
false;
1365 resolve_mask |= QFont::FixedPitchResolved;
1369
1370
1371
1372
1373bool QFont::kerning()
const
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389void QFont::setKerning(
bool enable)
1391 if ((resolve_mask & QFont::KerningResolved) && d->kerning == enable)
1394 QFontPrivate::detachButKeepEngineData(
this);
1396 d->kerning = enable;
1397 resolve_mask |= QFont::KerningResolved;
1401
1402
1403
1404
1405
1406
1407
1408QFont::StyleStrategy QFont::styleStrategy()
const
1410 return (StyleStrategy) d->request.styleStrategy;
1414
1415
1416
1417
1418
1419
1420
1421QFont::StyleHint QFont::styleHint()
const
1423 return (StyleHint) d->request.styleHint;
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536void QFont::setStyleHint(StyleHint hint, StyleStrategy strategy)
1538 if ((resolve_mask & (QFont::StyleHintResolved | QFont::StyleStrategyResolved)) &&
1539 (StyleHint) d->request.styleHint == hint &&
1540 (StyleStrategy) d->request.styleStrategy == strategy)
1545 d->request.styleHint = hint;
1546 d->request.styleStrategy = strategy;
1547 resolve_mask |= QFont::StyleHintResolved;
1548 resolve_mask |= QFont::StyleStrategyResolved;
1553
1554
1555
1556
1557void QFont::setStyleStrategy(StyleStrategy s)
1559 if ((resolve_mask & QFont::StyleStrategyResolved) &&
1560 s == (StyleStrategy)d->request.styleStrategy)
1565 d->request.styleStrategy = s;
1566 resolve_mask |= QFont::StyleStrategyResolved;
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1591
1592
1593
1594
1595int QFont::stretch()
const
1597 return d->request.stretch;
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619void QFont::setStretch(
int factor)
1621 if (factor < 0 || factor > 4000) {
1622 qWarning(
"QFont::setStretch: Parameter '%d' out of range", factor);
1626 if ((resolve_mask & QFont::StretchResolved) &&
1627 d->request.stretch == (uint)factor)
1632 d->request.stretch = (uint)factor;
1633 resolve_mask |= QFont::StretchResolved;
1637
1638
1639
1640
1641
1642
1643
1644
1647
1648
1649
1650
1651
1652qreal QFont::letterSpacing()
const
1654 return d->letterSpacing.toReal();
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669void QFont::setLetterSpacing(SpacingType type, qreal spacing)
1671 const QFixed newSpacing = QFixed::fromReal(spacing);
1672 const bool absoluteSpacing = type == AbsoluteSpacing;
1673 if ((resolve_mask & QFont::LetterSpacingResolved) &&
1674 d->letterSpacingIsAbsolute == absoluteSpacing &&
1675 d->letterSpacing == newSpacing)
1678 QFontPrivate::detachButKeepEngineData(
this);
1680 d->letterSpacing = newSpacing;
1681 d->letterSpacingIsAbsolute = absoluteSpacing;
1682 resolve_mask |= QFont::LetterSpacingResolved;
1686
1687
1688
1689
1690
1691QFont::SpacingType QFont::letterSpacingType()
const
1693 return d->letterSpacingIsAbsolute ? AbsoluteSpacing : PercentageSpacing;
1697
1698
1699
1700
1701
1702qreal QFont::wordSpacing()
const
1704 return d->wordSpacing.toReal();
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721void QFont::setWordSpacing(qreal spacing)
1723 const QFixed newSpacing = QFixed::fromReal(spacing);
1724 if ((resolve_mask & QFont::WordSpacingResolved) &&
1725 d->wordSpacing == newSpacing)
1728 QFontPrivate::detachButKeepEngineData(
this);
1730 d->wordSpacing = newSpacing;
1731 resolve_mask |= QFont::WordSpacingResolved;
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1749
1750
1751
1752
1753
1754
1755
1756void QFont::setCapitalization(Capitalization caps)
1758 if ((resolve_mask & QFont::CapitalizationResolved) &&
1759 capitalization() == caps)
1762 QFontPrivate::detachButKeepEngineData(
this);
1765 resolve_mask |= QFont::CapitalizationResolved;
1769
1770
1771
1772
1773
1774QFont::Capitalization QFont::capitalization()
const
1776 return static_cast<QFont::Capitalization> (d->capital);
1780
1781
1782
1783
1784
1785bool QFont::exactMatch()
const
1787 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
1788 Q_ASSERT(engine !=
nullptr);
1789 return d->request.exactMatch(engine->fontDef);
1793
1794
1795
1796
1797
1798
1799
1800
1801bool QFont::operator==(
const QFont &f)
const
1804 || (f.d->request == d->request
1805 && f.d->request.pointSize == d->request.pointSize
1806 && f.d->underline == d->underline
1807 && f.d->overline == d->overline
1808 && f.d->strikeOut == d->strikeOut
1809 && f.d->kerning == d->kerning
1810 && f.d->capital == d->capital
1811 && f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
1812 && f.d->letterSpacing == d->letterSpacing
1813 && f.d->wordSpacing == d->wordSpacing
1814 && f.d->features == d->features
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830bool QFont::operator<(
const QFont &f)
const
1832 if (f.d == d)
return false;
1834 const QFontDef &r1 = f.d->request;
1835 const QFontDef &r2 = d->request;
1836 if (r1.pointSize != r2.pointSize)
return r1.pointSize < r2.pointSize;
1837 if (r1.pixelSize != r2.pixelSize)
return r1.pixelSize < r2.pixelSize;
1838 if (r1.weight != r2.weight)
return r1.weight < r2.weight;
1839 if (r1.style != r2.style)
return r1.style < r2.style;
1840 if (r1.stretch != r2.stretch)
return r1.stretch < r2.stretch;
1841 if (r1.styleHint != r2.styleHint)
return r1.styleHint < r2.styleHint;
1842 if (r1.styleStrategy != r2.styleStrategy)
return r1.styleStrategy < r2.styleStrategy;
1843 if (r1.families != r2.families)
return r1.families < r2.families;
1844 if (f.d->capital != d->capital)
return f.d->capital < d->capital;
1846 if (f.d->letterSpacingIsAbsolute != d->letterSpacingIsAbsolute)
return f.d->letterSpacingIsAbsolute < d->letterSpacingIsAbsolute;
1847 if (f.d->letterSpacing != d->letterSpacing)
return f.d->letterSpacing < d->letterSpacing;
1848 if (f.d->wordSpacing != d->wordSpacing)
return f.d->wordSpacing < d->wordSpacing;
1850 int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
1851 int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
1852 if (f1attrs != f2attrs)
return f1attrs < f2attrs;
1854 if (d->features.size() != f.d->features.size())
1855 return f.d->features.size() < d->features.size();
1858 auto it = d->features.constBegin();
1859 auto jt = f.d->features.constBegin();
1860 for (; it != d->features.constEnd(); ++it, ++jt) {
1861 if (it.key() != jt.key())
1862 return jt.key() < it.key();
1863 if (it.value() != jt.value())
1864 return jt.value() < it.value();
1868 if (r1.variableAxisValues.size() != r2.variableAxisValues.size())
1869 return r1.variableAxisValues.size() < r2.variableAxisValues.size();
1872 auto it = r1.variableAxisValues.constBegin();
1873 auto jt = r2.variableAxisValues.constBegin();
1874 for (; it != r1.variableAxisValues.constEnd(); ++it, ++jt) {
1875 if (it.key() != jt.key())
1876 return jt.key() < it.key();
1877 if (it.value() != jt.value())
1878 return jt.value() < it.value();
1887
1888
1889
1890
1891
1892
1893
1894
1895bool QFont::operator!=(
const QFont &f)
const
1897 return !(operator==(f));
1901
1902
1903QFont::operator QVariant()
const
1905 return QVariant::fromValue(*
this);
1909
1910
1911
1912
1913
1914
1915bool QFont::isCopyOf(
const QFont & f)
const
1921
1922
1923
1924QFont QFont::resolve(
const QFont &other)
const
1926 if (resolve_mask == 0 || (resolve_mask == other.resolve_mask && *
this == other)) {
1928 o.resolve_mask = resolve_mask;
1934 font.d->resolve(resolve_mask, other.d.data());
1940
1941
1942
1945
1946
1947
1951
1952
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968QString QFont::substitute(
const QString &familyName)
1970 QFontSubst *fontSubst = globalFontSubst();
1971 Q_ASSERT(fontSubst !=
nullptr);
1972 QFontSubst::ConstIterator it = fontSubst->constFind(familyName.toLower());
1973 if (it != fontSubst->constEnd() && !(*it).isEmpty())
1974 return (*it).first();
1981
1982
1983
1984
1985
1986
1987
1988
1989QStringList QFont::substitutes(
const QString &familyName)
1991 QFontSubst *fontSubst = globalFontSubst();
1992 Q_ASSERT(fontSubst !=
nullptr);
1993 return fontSubst->value(familyName.toLower(), QStringList());
1998
1999
2000
2001
2002
2003
2004
2005
2006void QFont::insertSubstitution(
const QString &familyName,
2007 const QString &substituteName)
2009 QFontSubst *fontSubst = globalFontSubst();
2010 Q_ASSERT(fontSubst !=
nullptr);
2011 QStringList &list = (*fontSubst)[familyName.toLower()];
2012 QString s = substituteName.toLower();
2013 if (!list.contains(s))
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028void QFont::insertSubstitutions(
const QString &familyName,
2029 const QStringList &substituteNames)
2031 QFontSubst *fontSubst = globalFontSubst();
2032 Q_ASSERT(fontSubst !=
nullptr);
2033 QStringList &list = (*fontSubst)[familyName.toLower()];
2034 for (
const QString &substituteName : substituteNames) {
2035 const QString lowerSubstituteName = substituteName.toLower();
2036 if (!list.contains(lowerSubstituteName))
2037 list.append(lowerSubstituteName);
2042
2043
2044
2045
2046
2047void QFont::removeSubstitutions(
const QString &familyName)
2049 QFontSubst *fontSubst = globalFontSubst();
2050 Q_ASSERT(fontSubst !=
nullptr);
2051 fontSubst->remove(familyName.toLower());
2055
2056
2057
2058
2059QStringList QFont::substitutions()
2061 QFontSubst *fontSubst = globalFontSubst();
2062 Q_ASSERT(fontSubst !=
nullptr);
2063 QStringList ret = fontSubst->keys();
2069#ifndef QT_NO_DATASTREAM
2071
2072
2073
2076 Q_ASSERT(f !=
nullptr);
2078 if (f->request.style)
2086 if (f->request.fixedPitch)
2090 if (version >= QDataStream::Qt_4_0) {
2094 if (f->request.style == QFont::StyleOblique)
2101 Q_ASSERT(f !=
nullptr);
2103 if (f->request.ignorePitch)
2105 if (f->letterSpacingIsAbsolute)
2111
2112
2113
2116 Q_ASSERT(f !=
nullptr);
2117 f->request.style = (bits & 0x01) != 0 ? QFont::StyleItalic : QFont::StyleNormal;
2118 f->underline = (bits & 0x02) != 0;
2119 f->overline = (bits & 0x40) != 0;
2120 f->strikeOut = (bits & 0x04) != 0;
2121 f->request.fixedPitch = (bits & 0x08) != 0;
2123 if (version >= QDataStream::Qt_4_0)
2124 f->kerning = (bits & 0x10) != 0;
2125 if ((bits & 0x80) != 0)
2126 f->request.style = QFont::StyleOblique;
2131 Q_ASSERT(f !=
nullptr);
2132 f->request.ignorePitch = (bits & 0x01) != 0;
2133 f->letterSpacingIsAbsolute = (bits & 0x02) != 0;
2138
2139
2140
2141
2142
2143QString QFont::key()
const
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174QString QFont::toString()
const
2176 const QChar comma(u',');
2177 QString fontDescription = family() + comma +
2178 QString::number( pointSizeF()) + comma +
2179 QString::number( pixelSize()) + comma +
2180 QString::number((
int) styleHint()) + comma +
2181 QString::number( weight()) + comma +
2182 QString::number((
int) style()) + comma +
2183 QString::number((
int) underline()) + comma +
2184 QString::number((
int) strikeOut()) + comma +
2185 QString::number((
int)fixedPitch()) + comma +
2186 QString::number((
int)
false) + comma +
2187 QString::number((
int)capitalization()) + comma +
2188 QString::number((
int)letterSpacingType()) + comma +
2189 QString::number(letterSpacing()) + comma +
2190 QString::number(wordSpacing()) + comma +
2191 QString::number(stretch()) + comma +
2192 QString::number((
int)styleStrategy());
2194 QString fontStyle = styleName();
2195 if (!fontStyle.isEmpty())
2196 fontDescription += comma + fontStyle;
2198 return fontDescription;
2202
2203
2204
2205
2208 return qHash(QFontPrivate::get(font)->request, seed);
2213
2214
2215
2216
2217
2218
2219bool QFont::fromString(
const QString &descrip)
2221 const auto sr = QStringView(descrip).trimmed();
2222 const auto l = sr.split(u',');
2223 const int count = l.size();
2224 if (!count || (count > 2 && count < 9) || count == 9 || count > 17 ||
2225 l.first().isEmpty()) {
2226 qWarning(
"QFont::fromString: Invalid description '%s'",
2227 descrip.isEmpty() ?
"(empty)" : descrip.toLatin1().data());
2231 setFamily(l[0].toString());
2232 if (count > 1 && l[1].toDouble() > 0.0)
2233 setPointSizeF(l[1].toDouble());
2235 setStyleHint((StyleHint) l[2].toInt());
2236 setWeight(QFont::Weight(l[3].toInt()));
2237 setItalic(l[4].toInt());
2238 setUnderline(l[5].toInt());
2239 setStrikeOut(l[6].toInt());
2240 setFixedPitch(l[7].toInt());
2241 }
else if (count >= 10) {
2242 if (l[2].toInt() > 0)
2243 setPixelSize(l[2].toInt());
2244 setStyleHint((StyleHint) l[3].toInt());
2246 setWeight(QFont::Weight(l[4].toInt()));
2248 setWeight(QFont::Weight(qt_legacyToOpenTypeWeight(l[4].toInt())));
2249 setStyle((QFont::Style)l[5].toInt());
2250 setUnderline(l[6].toInt());
2251 setStrikeOut(l[7].toInt());
2252 setFixedPitch(l[8].toInt());
2254 setCapitalization((Capitalization)l[10].toInt());
2255 setLetterSpacing((SpacingType)l[11].toInt(), l[12].toDouble());
2256 setWordSpacing(l[13].toDouble());
2257 setStretch(l[14].toInt());
2258 setStyleStrategy((StyleStrategy)l[15].toInt());
2260 if (count == 11 || count == 17)
2261 d->request.styleName = l[count - 1].toString();
2263 d->request.styleName.clear();
2266 if (count >= 9 && !d->request.fixedPitch)
2267 d->request.ignorePitch =
true;
2273
2274
2275
2276
2277
2278
2279void QFont::initialize()
2284
2285
2286
2287
2288void QFont::cleanup()
2290 QFontCache::cleanup();
2294
2295
2296
2297void QFont::cacheStatistics()
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2332
2333
2334
2335
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2351
2352
2353
2354
2355
2358
2359
2360
2363
2364
2365
2366
2367
2368
2371
2372
2373
2374
2375
2376
2379
2380
2381
2382
2383
2384
2387
2388
2389
2390
2391
2392
2393
2396
2397
2398
2399
2400
2401
2402
2403
2404std::optional<QFont::Tag> QFont::Tag::fromString(QAnyStringView view)
noexcept
2406 if (view.size() != 4) {
2407 qWarning(
"The tag name must be exactly 4 characters long!");
2408 return std::nullopt;
2410 const QFont::Tag maybeTag = view.visit([](
auto view) {
2411 using CharType =
decltype(view.at(0));
2412 if constexpr (std::is_same_v<CharType,
char>) {
2413 const char bytes[5] = { view.at(0), view.at(1), view.at(2), view.at(3), 0 };
2416 const char bytes[5] = { view.at(0).toLatin1(), view.at(1).toLatin1(),
2417 view.at(2).toLatin1(), view.at(3).toLatin1(), 0 };
2421 return maybeTag.isValid() ? std::optional<Tag>(maybeTag) : std::nullopt;
2425
2426
2427
2428
2429
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469void QFont::setVariableAxis(Tag tag,
float value)
2471 if (tag.isValid()) {
2472 if (resolve_mask & QFont::VariableAxesResolved && d->hasVariableAxis(tag, value))
2477 d->setVariableAxis(tag, value);
2478 resolve_mask |= QFont::VariableAxesResolved;
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492void QFont::unsetVariableAxis(Tag tag)
2494 if (tag.isValid()) {
2497 d->unsetVariableAxis(tag);
2498 resolve_mask |= QFont::VariableAxesResolved;
2503
2504
2505
2506
2507
2508
2509
2510
2511QList<QFont::Tag> QFont::variableAxisTags()
const
2513 return d->request.variableAxisValues.keys();
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526float QFont::variableAxisValue(Tag tag)
const
2528 return d->request.variableAxisValues.value(tag);
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541bool QFont::isVariableAxisSet(Tag tag)
const
2543 return d->request.variableAxisValues.contains(tag);
2547
2548
2549
2550
2551
2552
2553
2554
2555void QFont::clearVariableAxes()
2557 if (d->request.variableAxisValues.isEmpty())
2561 d->request.variableAxisValues.clear();
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601void QFont::setFeature(Tag tag, quint32 value)
2603 if (tag.isValid()) {
2604 d->detachButKeepEngineData(
this);
2605 d->setFeature(tag, value);
2606 resolve_mask |= QFont::FeaturesResolved;
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625void QFont::unsetFeature(Tag tag)
2627 if (tag.isValid()) {
2628 d->detachButKeepEngineData(
this);
2629 d->unsetFeature(tag);
2630 resolve_mask |= QFont::FeaturesResolved;
2635
2636
2637
2638
2639
2640
2641
2642
2643QList<QFont::Tag> QFont::featureTags()
const
2645 return d->features.keys();
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658quint32 QFont::featureValue(Tag tag)
const
2660 return d->features.value(tag);
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673bool QFont::isFeatureSet(Tag tag)
const
2675 return d->features.contains(tag);
2679
2680
2681
2682
2683
2684
2685
2686
2687void QFont::clearFeatures()
2689 if (d->features.isEmpty())
2692 d->detachButKeepEngineData(
this);
2693 d->features.clear();
2698 QFont::StyleHint styleHint,
2699 QFontDatabasePrivate::ExtendedScript script);
2702
2703
2704
2705
2706
2707
2708
2709QString QFont::defaultFamily()
const
2711 const QStringList fallbacks = qt_fallbacksForFamily(QString(),
2713 QFont::StyleHint(d->request.styleHint),
2714 QFontDatabasePrivate::Script_Common);
2715 if (!fallbacks.isEmpty())
2716 return fallbacks.first();
2721
2722
2723
2724
2725
2726
2727
2728
2730QStringList QFont::families()
const
2732 return d->request.families;
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2752void QFont::setFamilies(
const QStringList &families)
2754 if ((resolve_mask & QFont::FamiliesResolved) && d->request.families == families)
2757 d->request.families = families;
2758 resolve_mask |= QFont::FamiliesResolved;
2763
2764
2765#ifndef QT_NO_DATASTREAM
2768
2769
2770
2771
2772
2773
2774
2775QDataStream &operator<<(QDataStream &s,
const QFont &font)
2777 if (s.version() == 1) {
2778 s << font.d->request.families.constFirst().toLatin1();
2780 s << font.d->request.families.constFirst();
2781 if (s.version() >= QDataStream::Qt_5_4)
2782 s << font.d->request.styleName;
2785 if (s.version() >= QDataStream::Qt_4_0) {
2787 double pointSize = font.d->request.pointSize;
2788 qint32 pixelSize = font.d->request.pixelSize;
2791 }
else if (s.version() <= 3) {
2792 qint16 pointSize = (qint16) (font.d->request.pointSize * 10);
2793 if (pointSize < 0) {
2794 pointSize = (qint16)QFontInfo(font).pointSize() * 10;
2798 s << (qint16) (font.d->request.pointSize * 10);
2799 s << (qint16) font.d->request.pixelSize;
2802 s << (quint8) font.d->request.styleHint;
2803 if (s.version() >= QDataStream::Qt_3_1) {
2806 if (s.version() >= QDataStream::Qt_5_4)
2807 s << (quint16) font.d->request.styleStrategy;
2809 s << (quint8) font.d->request.styleStrategy;
2812 if (s.version() < QDataStream::Qt_6_0)
2813 s << quint8(0) << quint8(qt_openTypeToLegacyWeight(font.d->request.weight));
2815 s << quint16(font.d->request.weight);
2817 s << get_font_bits(s.version(), font.d.data());
2818 if (s.version() >= QDataStream::Qt_4_3)
2819 s << (quint16)font.d->request.stretch;
2820 if (s.version() >= QDataStream::Qt_4_4)
2821 s << get_extended_font_bits(font.d.data());
2822 if (s.version() >= QDataStream::Qt_4_5) {
2823 s << font.d->letterSpacing.value();
2824 s << font.d->wordSpacing.value();
2826 if (s.version() >= QDataStream::Qt_5_4)
2827 s << (quint8)font.d->request.hintingPreference;
2828 if (s.version() >= QDataStream::Qt_5_6)
2829 s << (quint8)font.d->capital;
2830 if (s.version() >= QDataStream::Qt_5_13) {
2831 if (s.version() < QDataStream::Qt_6_0)
2832 s << font.d->request.families.mid(1);
2834 s << font.d->request.families;
2836 if (s.version() >= QDataStream::Qt_6_6)
2837 s << font.d->features;
2838 if (s.version() >= QDataStream::Qt_6_7)
2839 s << font.d->request.variableAxisValues;
2845
2846
2847
2848
2849
2850
2851
2854 font.d =
new QFontPrivate;
2855 font.resolve_mask = QFont::AllPropertiesResolved;
2857 quint8 styleHint, bits;
2858 quint16 styleStrategy = QFont::PreferDefault;
2860 if (s.version() == 1) {
2863 font.d->request.families = QStringList(QString::fromLatin1(fam));
2867 font.d->request.families = QStringList(fam);
2868 if (s.version() >= QDataStream::Qt_5_4)
2869 s >> font.d->request.styleName;
2872 if (s.version() >= QDataStream::Qt_4_0) {
2878 font.d->request.pointSize = qreal(pointSize);
2879 font.d->request.pixelSize = pixelSize;
2881 qint16 pointSize, pixelSize = -1;
2883 if (s.version() >= 4)
2885 font.d->request.pointSize = qreal(pointSize / 10.);
2886 font.d->request.pixelSize = pixelSize;
2889 if (s.version() >= QDataStream::Qt_3_1) {
2890 if (s.version() >= QDataStream::Qt_5_4) {
2893 quint8 tempStyleStrategy;
2894 s >> tempStyleStrategy;
2895 styleStrategy = tempStyleStrategy;
2899 if (s.version() < QDataStream::Qt_6_0) {
2904 font.d->request.weight = qt_legacyToOpenTypeWeight(weight);
2908 font.d->request.weight = weight;
2913 font.d->request.styleHint = styleHint;
2914 font.d->request.styleStrategy = styleStrategy;
2916 set_font_bits(s.version(), bits, font.d.data());
2918 if (s.version() >= QDataStream::Qt_4_3) {
2921 font.d->request.stretch = stretch;
2924 if (s.version() >= QDataStream::Qt_4_4) {
2925 quint8 extendedBits;
2927 set_extended_font_bits(extendedBits, font.d.data());
2929 if (s.version() >= QDataStream::Qt_4_5) {
2932 font.d->letterSpacing.setValue(value);
2934 font.d->wordSpacing.setValue(value);
2936 if (s.version() >= QDataStream::Qt_5_4) {
2939 font.d->request.hintingPreference = QFont::HintingPreference(value);
2941 if (s.version() >= QDataStream::Qt_5_6) {
2944 font.d->capital = QFont::Capitalization(value);
2946 if (s.version() >= QDataStream::Qt_5_13) {
2949 if (s.version() < QDataStream::Qt_6_0)
2950 font.d->request.families.append(value);
2952 font.d->request.families = value;
2954 if (s.version() >= QDataStream::Qt_6_6) {
2955 font.d->features.clear();
2956 s >> font.d->features;
2958 if (s.version() >= QDataStream::Qt_6_7) {
2959 font.d->request.variableAxisValues.clear();
2960 s >> font.d->request.variableAxisValues;
2966QDataStream &operator<<(QDataStream &stream, QFont::Tag tag)
2968 stream << tag.value();
2972QDataStream &
operator>>(QDataStream &stream, QFont::Tag &tag)
2976 if (
const auto maybeTag = QFont::Tag::fromValue(value))
2979 stream.setStatus(QDataStream::ReadCorruptData);
2987
2988
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081QFontInfo::QFontInfo(
const QFont &font)
3087
3088
3089QFontInfo::QFontInfo(
const QFontInfo &fi)
3095
3096
3097QFontInfo::~QFontInfo()
3102
3103
3104QFontInfo &QFontInfo::operator=(
const QFontInfo &fi)
3111
3112
3113
3114
3117
3118
3119
3120
3121QString QFontInfo::family()
const
3123 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3124 Q_ASSERT(engine !=
nullptr);
3125 return engine->fontDef.families.isEmpty() ? QString() : engine->fontDef.families.constFirst();
3129
3130
3131
3132
3133
3134
3135
3136QString QFontInfo::styleName()
const
3138 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3139 Q_ASSERT(engine !=
nullptr);
3140 return engine->fontDef.styleName;
3144
3145
3146
3147
3148int QFontInfo::pointSize()
const
3150 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3151 Q_ASSERT(engine !=
nullptr);
3152 return qRound(engine->fontDef.pointSize);
3156
3157
3158
3159
3160qreal QFontInfo::pointSizeF()
const
3162 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3163 Q_ASSERT(engine !=
nullptr);
3164 return engine->fontDef.pointSize;
3168
3169
3170
3171
3172int QFontInfo::pixelSize()
const
3174 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3175 Q_ASSERT(engine !=
nullptr);
3176 return engine->fontDef.pixelSize;
3180
3181
3182
3183
3184bool QFontInfo::italic()
const
3186 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3187 Q_ASSERT(engine !=
nullptr);
3188 return engine->fontDef.style != QFont::StyleNormal;
3192
3193
3194
3195
3196QFont::Style QFontInfo::style()
const
3198 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3199 Q_ASSERT(engine !=
nullptr);
3200 return (QFont::Style)engine->fontDef.style;
3204#if QT_DEPRECATED_SINCE(6
, 0
)
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218int QFontInfo::legacyWeight()
const
3220 return qt_openTypeToLegacyWeight(weight());
3226
3227
3228
3229
3230int QFontInfo::weight()
const
3232 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3233 Q_ASSERT(engine !=
nullptr);
3234 return engine->fontDef.weight;
3239
3240
3241
3242
3243
3244
3245
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257bool QFontInfo::underline()
const
3259 return d->underline;
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272bool QFontInfo::overline()
const
3278
3279
3280
3281
3282
3283
3284
3285bool QFontInfo::strikeOut()
const
3287 return d->strikeOut;
3291
3292
3293
3294
3295bool QFontInfo::fixedPitch()
const
3297 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3298 Q_ASSERT(engine !=
nullptr);
3300 if (!engine->fontDef.fixedPitchComputed) {
3301 QChar ch[2] = { u'i', u'm' };
3302 QGlyphLayoutArray<2> g;
3304 if (engine->stringToCMap(ch, 2, &g, &l, {}) < 0)
3307 engine->fontDef.fixedPitch = g.advances[0] == g.advances[1];
3308 engine->fontDef.fixedPitchComputed =
true;
3311 return engine->fontDef.fixedPitch;
3315
3316
3317
3318
3319
3320
3321QFont::StyleHint QFontInfo::styleHint()
const
3323 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3324 Q_ASSERT(engine !=
nullptr);
3325 return (QFont::StyleHint) engine->fontDef.styleHint;
3329
3330
3331
3332
3333
3334bool QFontInfo::exactMatch()
const
3336 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3337 Q_ASSERT(engine !=
nullptr);
3338 return d->request.exactMatch(engine->fontDef);
3342
3343
3344
3345
3346
3347
3348
3349QList<QFontVariableAxis> QFontInfo::variableAxes()
const
3351 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3352 Q_ASSERT(engine !=
nullptr);
3353 return engine->variableAxes();
3361using namespace std::chrono_literals;
3363#ifdef QFONTCACHE_DEBUG
3365static constexpr auto fast_timeout = 1s;
3366static constexpr auto slow_timeout = 5s;
3372#ifndef QFONTCACHE_MIN_COST
3373# define QFONTCACHE_MIN_COST 4
*1024
3378QFontCache *QFontCache::instance()
3380 QFontCache *&fontCache = theFontCache()->localData();
3382 fontCache =
new QFontCache;
3386void QFontCache::cleanup()
3388 QThreadStorage<QFontCache *> *cache =
nullptr;
3390 cache = theFontCache();
3391 } QT_CATCH (
const std::bad_alloc &) {
3394 if (cache && cache->hasLocalData())
3395 cache->setLocalData(
nullptr);
3398Q_CONSTINIT
static QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(0);
3400QFontCache::QFontCache()
3401 : QObject(), total_cost(0), max_cost(min_cost),
3402 current_timestamp(0), fast(
false),
3403 autoClean(QGuiApplication::instance()
3404 && (QGuiApplication::instance()->thread() == QThread::currentThread())),
3405 m_id(font_cache_id.fetchAndAddRelaxed(1) + 1)
3409QFontCache::~QFontCache()
3414void QFontCache::clear()
3417 EngineDataCache::Iterator it = engineDataCache.begin(),
3418 end = engineDataCache.end();
3420 QFontEngineData *data = it.value();
3421 for (
int i = 0; i < QFontDatabasePrivate::ScriptCount; ++i) {
3422 if (data->engines[i]) {
3423 if (!data->engines[i]->ref.deref()) {
3424 Q_ASSERT(engineCacheCount.value(data->engines[i]) == 0);
3425 delete data->engines[i];
3427 data->engines[i] =
nullptr;
3430 if (!data->ref.deref()) {
3433 FC_DEBUG(
"QFontCache::clear: engineData %p still has refcount %d",
3434 data, data->ref.loadRelaxed());
3440 engineDataCache.clear();
3443 bool mightHaveEnginesLeftForCleanup;
3445 mightHaveEnginesLeftForCleanup =
false;
3446 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
3448 QFontEngine *engine = it.value().data;
3450 const int cacheCount = --engineCacheCount[engine];
3451 Q_ASSERT(cacheCount >= 0);
3452 if (!engine->ref.deref()) {
3453 Q_ASSERT(cacheCount == 0);
3454 mightHaveEnginesLeftForCleanup = engine->type() == QFontEngine::Multi;
3456 }
else if (cacheCount == 0) {
3457 FC_DEBUG(
"QFontCache::clear: engine %p still has refcount %d",
3458 engine, engine->ref.loadRelaxed());
3460 it.value().data =
nullptr;
3463 }
while (mightHaveEnginesLeftForCleanup);
3465 engineCache.clear();
3466 engineCacheCount.clear();
3470 max_cost = min_cost;
3474QFontEngineData *QFontCache::findEngineData(
const QFontDef &def)
const
3476 EngineDataCache::ConstIterator it = engineDataCache.constFind(def);
3477 if (it == engineDataCache.constEnd())
3484void QFontCache::insertEngineData(
const QFontDef &def, QFontEngineData *engineData)
3486#ifdef QFONTCACHE_DEBUG
3487 FC_DEBUG(
"QFontCache: inserting new engine data %p", engineData);
3488 if (engineDataCache.contains(def)) {
3489 FC_DEBUG(
" QFontCache already contains engine data %p for key=(%g %g %d %d %d)",
3490 engineDataCache.value(def), def.pointSize,
3491 def.pixelSize, def.weight, def.style, def.fixedPitch);
3494 Q_ASSERT(!engineDataCache.contains(def));
3496 engineData->ref.ref();
3501 engineDataCache.insert(def, engineData);
3502 increaseCost(
sizeof(QFontEngineData));
3505QFontEngine *QFontCache::findEngine(
const Key &key)
3507 EngineCache::Iterator it = engineCache.find(key),
3508 end = engineCache.end();
3509 if (it == end)
return nullptr;
3511 Q_ASSERT(it.value().data !=
nullptr);
3512 Q_ASSERT(key.multi == (it.value().data->type() == QFontEngine::Multi));
3515 updateHitCountAndTimeStamp(it.value());
3517 return it.value().data;
3520void QFontCache::updateHitCountAndTimeStamp(Engine &value)
3523 value.timestamp = ++current_timestamp;
3525 FC_DEBUG(
"QFontCache: found font engine\n"
3526 " %p: timestamp %4u hits %3u ref %2d/%2d, type %d",
3527 value.data, value.timestamp, value.hits,
3528 value.data->ref.loadRelaxed(), engineCacheCount.value(value.data),
3529 value.data->type());
3532void QFontCache::insertEngine(
const Key &key, QFontEngine *engine,
bool insertMulti)
3534 Q_ASSERT(engine !=
nullptr);
3535 Q_ASSERT(key.multi == (engine->type() == QFontEngine::Multi));
3537#ifdef QFONTCACHE_DEBUG
3538 FC_DEBUG(
"QFontCache: inserting new engine %p, refcount %d", engine, engine->ref.loadRelaxed());
3539 if (!insertMulti && engineCache.contains(key)) {
3540 FC_DEBUG(
" QFontCache already contains engine %p for key=(%g %g %d %d %d)",
3541 engineCache.value(key).data, key.def.pointSize,
3542 key.def.pixelSize, key.def.weight, key.def.style, key.def.fixedPitch);
3550 Engine data(engine);
3551 data.timestamp = ++current_timestamp;
3554 engineCache.insert(key, data);
3556 engineCache.replace(key, data);
3558 if (++engineCacheCount[engine] == 1)
3559 increaseCost(engine->cache_cost);
3562void QFontCache::increaseCost(uint cost)
3564 cost = (cost + 512) / 1024;
3565 cost = cost > 0 ? cost : 1;
3568 FC_DEBUG(
" COST: increased %u kb, total_cost %u kb, max_cost %u kb",
3569 cost, total_cost, max_cost);
3571 if (total_cost > max_cost) {
3572 max_cost = total_cost;
3577 if (!timer.isActive() || ! fast) {
3578 FC_DEBUG(
" TIMER: starting fast timer (%d s)",
static_cast<
int>(fast_timeout.count()));
3580 timer.start(fast_timeout,
this);
3586void QFontCache::decreaseCost(uint cost)
3588 cost = (cost + 512) / 1024;
3589 cost = cost > 0 ? cost : 1;
3590 Q_ASSERT(cost <= total_cost);
3593 FC_DEBUG(
" COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
3594 cost, total_cost, max_cost);
3597void QFontCache::timerEvent(QTimerEvent *)
3599 FC_DEBUG(
"QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
3602 if (total_cost <= max_cost && max_cost <= min_cost) {
3603 FC_DEBUG(
" cache redused sufficiently, stopping timer");
3613void QFontCache::decreaseCache()
3616 uint in_use_cost = 0;
3622 const uint engine_data_cost =
3623 sizeof(QFontEngineData) > 1024 ?
sizeof(QFontEngineData) : 1024;
3625 EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
3626 end = engineDataCache.constEnd();
3627 for (; it != end; ++it) {
3628 FC_DEBUG(
" %p: ref %2d", it.value(),
int(it.value()->ref.loadRelaxed()));
3630 if (it.value()->ref.loadRelaxed() != 1)
3631 in_use_cost += engine_data_cost;
3638 EngineCache::ConstIterator it = engineCache.constBegin(),
3639 end = engineCache.constEnd();
3640 for (; it != end; ++it) {
3641 FC_DEBUG(
" %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
3642 it.value().data, it.value().timestamp, it.value().hits,
3643 it.value().data->ref.loadRelaxed(), engineCacheCount.value(it.value().data),
3644 it.value().data->cache_cost);
3646 if (it.value().data->ref.loadRelaxed() > engineCacheCount.value(it.value().data))
3647 in_use_cost += it.value().data->cache_cost / engineCacheCount.value(it.value().data);
3651 in_use_cost += engineCache.size();
3654 in_use_cost = (in_use_cost + 512) / 1024;
3657
3658
3659
3660
3661
3662
3663
3664 uint new_max_cost = qMax(qMax(max_cost / 2, in_use_cost), min_cost);
3666 FC_DEBUG(
" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
3667 in_use_cost, total_cost, max_cost, new_max_cost);
3670 if (new_max_cost == max_cost) {
3672 FC_DEBUG(
" cannot shrink cache, slowing timer");
3674 if (timer.isActive()) {
3675 timer.start(slow_timeout,
this);
3680 }
else if (! fast) {
3681 FC_DEBUG(
" dropping into passing gear");
3683 timer.start(fast_timeout,
this);
3688 max_cost = new_max_cost;
3694 EngineDataCache::Iterator it = engineDataCache.begin();
3695 while (it != engineDataCache.end()) {
3696 if (it.value()->ref.loadRelaxed() == 1) {
3698 decreaseCost(
sizeof(QFontEngineData));
3699 it.value()->ref.deref();
3701 it = engineDataCache.erase(it);
3711 bool cost_decreased;
3713 cost_decreased =
false;
3715 EngineCache::Iterator it = engineCache.begin(),
3716 end = engineCache.end();
3719 uint least_popular = ~0u;
3721 EngineCache::Iterator jt = end;
3723 for ( ; it != end; ++it) {
3724 if (it.value().data->ref.loadRelaxed() != engineCacheCount.value(it.value().data))
3727 if (it.value().timestamp < oldest && it.value().hits <= least_popular) {
3728 oldest = it.value().timestamp;
3729 least_popular = it.value().hits;
3736 FC_DEBUG(
" %p: timestamp %4u hits %2u ref %2d/%2d, type %d",
3737 it.value().data, it.value().timestamp, it.value().hits,
3738 it.value().data->ref.loadRelaxed(), engineCacheCount.value(it.value().data),
3739 it.value().data->type());
3741 QFontEngine *fontEngine = it.value().data;
3743 it = engineCache.begin();
3744 while (it != engineCache.end()) {
3745 if (it.value().data == fontEngine) {
3746 fontEngine->ref.deref();
3747 it = engineCache.erase(it);
3753 Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
3754 decreaseCost(fontEngine->cache_cost);
3756 engineCacheCount.remove(fontEngine);
3758 cost_decreased =
true;
3760 }
while (cost_decreased && total_cost > max_cost);
3764#ifndef QT_NO_DEBUG_STREAM
3765QDebug operator<<(QDebug stream,
const QFont &font)
3767 QDebugStateSaver saver(stream);
3768 stream.nospace().noquote();
3771 if (stream.verbosity() == QDebug::DefaultVerbosity) {
3772 stream << font.toString() <<
")";
3776 QString fontDescription;
3777 QDebug debug(&fontDescription);
3780 const QFont defaultFont(
new QFontPrivate);
3782 for (
int property = QFont::SizeResolved; property < QFont::AllPropertiesResolved; property <<= 1) {
3783 const bool resolved = (font.resolve_mask & property) != 0;
3784 if (!resolved && stream.verbosity() == QDebug::MinimumVerbosity)
3787 #define QFONT_DEBUG_SKIP_DEFAULT(prop)
3788 if ((font.prop() == defaultFont.prop()) && stream.verbosity() == 1
)
3791 QDebugStateSaver saver(debug);
3794 case QFont::SizeResolved:
3795 if (font.pointSizeF() >= 0)
3796 debug << font.pointSizeF() <<
"pt";
3797 else if (font.pixelSize() >= 0)
3798 debug << font.pixelSize() <<
"px";
3802 case QFont::StyleHintResolved:
3804 debug.verbosity(1) << font.styleHint();
break;
3805 case QFont::StyleStrategyResolved:
3807 debug.verbosity(1) << font.styleStrategy();
break;
3808 case QFont::WeightResolved:
3809 debug.verbosity(1) << QFont::Weight(font.weight());
break;
3810 case QFont::StyleResolved:
3812 debug.verbosity(0) << font.style();
break;
3813 case QFont::UnderlineResolved:
3815 debug <<
"underline=" << font.underline();
break;
3816 case QFont::OverlineResolved:
3818 debug <<
"overline=" << font.overline();
break;
3819 case QFont::StrikeOutResolved:
3821 debug <<
"strikeOut=" << font.strikeOut();
break;
3822 case QFont::FixedPitchResolved:
3824 debug <<
"fixedPitch=" << font.fixedPitch();
break;
3825 case QFont::StretchResolved:
3827 debug.verbosity(0) << QFont::Stretch(font.stretch());
break;
3828 case QFont::KerningResolved:
3830 debug <<
"kerning=" << font.kerning();
break;
3831 case QFont::CapitalizationResolved:
3833 debug.verbosity(0) << font.capitalization();
break;
3834 case QFont::LetterSpacingResolved:
3836 debug <<
"letterSpacing=" << font.letterSpacing();
3837 debug.verbosity(0) <<
" (" << font.letterSpacingType() <<
")";
3839 case QFont::HintingPreferenceResolved:
3841 debug.verbosity(0) << font.hintingPreference();
break;
3842 case QFont::StyleNameResolved:
3844 debug <<
"styleName=" << font.styleName();
break;
3849 #undef QFONT_DEBUG_SKIP_DEFAULT
3854 if (stream.verbosity() > QDebug::MinimumVerbosity)
3855 debug.verbosity(0) <<
"resolveMask=" << QFlags<QFont::ResolveProperties>(font.resolve_mask);
3857 fontDescription.chop(2);
3859 stream << fontDescription <<
')';
3864QDebug operator<<(QDebug debug, QFont::Tag tag)
3866 QDebugStateSaver saver(debug);
3867 debug.noquote() << tag.toString();
3874#include "moc_qfont.cpp"
Combined button and popup list for selecting options.
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
Q_GUI_EXPORT int qt_openTypeToLegacyWeight(int weight)
static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
QRecursiveMutex * qt_fontdatabase_mutex()
static int convertWeights(int weight, bool inverted)
static QStringList splitIntoFamilies(const QString &family)
Q_GUI_EXPORT int qt_legacyToOpenTypeWeight(int weight)
static constexpr auto fast_timeout
QHash< QString, QStringList > QFontSubst
#define QFONT_DEBUG_SKIP_DEFAULT(prop)
#define QFONTCACHE_MIN_COST
#define QT_FONT_ENGINE_FROM_DATA(data, script)
Q_GUI_EXPORT int qt_defaultDpiY()
static constexpr auto slow_timeout
Q_GUI_EXPORT int qt_defaultDpiX()
static quint8 get_extended_font_bits(const QFontPrivate *f)
Q_GUI_EXPORT int qt_defaultDpi()
#define QFONTCACHE_DECREASE_TRIGGER_LIMIT
QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QFontDatabasePrivate::ExtendedScript script)
static quint8 get_font_bits(int version, const QFontPrivate *f)
static void set_extended_font_bits(quint8 bits, QFontPrivate *f)
Q_CONSTINIT Q_GUI_EXPORT bool qt_is_tty_app
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
bool exactMatch(const QFontDef &other) const