Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qfont.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfont.h"
5#include "qdebug.h"
6#include "qpaintdevice.h"
8#include "qfontmetrics.h"
9#include "qfontinfo.h"
10#include "qpainter.h"
11#include "qhash.h"
12#include "qdatastream.h"
14#include "qstringlist.h"
15#include "qscreen.h"
16
17#include "qthread.h"
18#include "qthreadstorage.h"
19
20#include "qfont_p.h"
21#include <private/qfontengine_p.h>
22#include <private/qpainter_p.h>
23#include <private/qtextengine_p.h>
24#include <limits.h>
25
26#include <qpa/qplatformscreen.h>
27#include <qpa/qplatformintegration.h>
28#include <qpa/qplatformfontdatabase.h>
29#include <QtGui/private/qguiapplication_p.h>
30
31#include <QtCore/QMutexLocker>
32#include <QtCore/QMutex>
33
34#include <algorithm>
35#include <array>
36
37// #define QFONTCACHE_DEBUG
38#ifdef QFONTCACHE_DEBUG
39# define FC_DEBUG qDebug
40#else
41# define FC_DEBUG if (false) qDebug
42#endif
43
45
46#ifndef QFONTCACHE_DECREASE_TRIGGER_LIMIT
47# define QFONTCACHE_DECREASE_TRIGGER_LIMIT 256
48#endif
49
50bool QFontDef::exactMatch(const QFontDef &other) const
51{
52 /*
53 QFontDef comparison is more complicated than just simple
54 per-member comparisons.
55
56 When comparing point/pixel sizes, either point or pixelsize
57 could be -1. in This case we have to compare the non negative
58 size value.
59
60 This test will fail if the point-sizes differ by 1/2 point or
61 more or they do not round to the same value. We have to do this
62 since our API still uses 'int' point-sizes in the API, but store
63 deci-point-sizes internally.
64
65 To compare the family members, we need to parse the font names
66 and compare the family/foundry strings separately. This allows
67 us to compare e.g. "Helvetica" and "Helvetica [Adobe]" with
68 positive results.
69 */
70 if (pixelSize != -1 && other.pixelSize != -1) {
71 if (pixelSize != other.pixelSize)
72 return false;
73 } else if (pointSize != -1 && other.pointSize != -1) {
74 if (pointSize != other.pointSize)
75 return false;
76 } else {
77 return false;
78 }
79
80 if (!ignorePitch && !other.ignorePitch && fixedPitch != other.fixedPitch)
81 return false;
82
83 if (stretch != 0 && other.stretch != 0 && stretch != other.stretch)
84 return false;
85
86 if (families.size() != other.families.size())
87 return false;
88
89 QString this_family, this_foundry, other_family, other_foundry;
90 for (int i = 0; i < families.size(); ++i) {
91 QFontDatabasePrivate::parseFontName(families.at(i), this_foundry, this_family);
92 QFontDatabasePrivate::parseFontName(other.families.at(i), other_foundry, other_family);
93 if (this_family != other_family || this_foundry != other_foundry)
94 return false;
95 }
96
97 if (variableAxisValues != other.variableAxisValues)
98 return false;
99
100 return (styleHint == other.styleHint
101 && styleStrategy == other.styleStrategy
102 && weight == other.weight
103 && style == other.style
104 && this_family == other_family
105 && (styleName.isEmpty() || other.styleName.isEmpty() || styleName == other.styleName)
106 && (this_foundry.isEmpty()
107 || other_foundry.isEmpty()
108 || this_foundry == other_foundry)
109 );
110}
111
112extern bool qt_is_tty_app;
113
114Q_GUI_EXPORT int qt_defaultDpiX()
115{
116 if (QCoreApplication::instance()->testAttribute(Qt::AA_Use96Dpi))
117 return 96;
118
119 if (qt_is_tty_app)
120 return 75;
121
122 if (const QScreen *screen = QGuiApplication::primaryScreen())
123 return qRound(screen->logicalDotsPerInchX());
124
125 //PI has not been initialised, or it is being initialised. Give a default dpi
126 return 100;
127}
128
129Q_GUI_EXPORT int qt_defaultDpiY()
130{
131 if (QCoreApplication::instance()->testAttribute(Qt::AA_Use96Dpi))
132 return 96;
133
134 if (qt_is_tty_app)
135 return 75;
136
137 if (const QScreen *screen = QGuiApplication::primaryScreen())
138 return qRound(screen->logicalDotsPerInchY());
139
140 //PI has not been initialised, or it is being initialised. Give a default dpi
141 return 100;
142}
143
144Q_GUI_EXPORT int qt_defaultDpi()
145{
146 return qt_defaultDpiY();
147}
148
149/* Helper function to convert between legacy Qt and OpenType font weights. */
150static int convertWeights(int weight, bool inverted)
151{
152 static constexpr std::array<int, 2> legacyToOpenTypeMap[] = {
153 { 0, QFont::Thin }, { 12, QFont::ExtraLight }, { 25, QFont::Light },
154 { 50, QFont::Normal }, { 57, QFont::Medium }, { 63, QFont::DemiBold },
155 { 75, QFont::Bold }, { 81, QFont::ExtraBold }, { 87, QFont::Black },
156 };
157
158 int closestDist = INT_MAX;
159 int result = -1;
160
161 // Go through and find the closest mapped value
162 for (auto mapping : legacyToOpenTypeMap) {
163 const int weightOld = mapping[ inverted];
164 const int weightNew = mapping[!inverted];
165 const int dist = qAbs(weightOld - weight);
166 if (dist < closestDist) {
167 result = weightNew;
168 closestDist = dist;
169 } else {
170 // Break early since following values will be further away
171 break;
172 }
173 }
174
175 return result;
176}
177
178// Splits the family string on a comma and returns the list based on that
179static QStringList splitIntoFamilies(const QString &family)
180{
181 QStringList familyList;
182 if (family.isEmpty())
183 return familyList;
184 const auto list = QStringView{family}.split(u',');
185 const int numFamilies = list.size();
186 familyList.reserve(numFamilies);
187 for (int i = 0; i < numFamilies; ++i) {
188 auto str = list.at(i).trimmed();
189 if ((str.startsWith(u'"') && str.endsWith(u'"'))
190 || (str.startsWith(u'\'') && str.endsWith(u'\''))) {
191 str = str.mid(1, str.size() - 2);
192 }
193 familyList << str.toString();
194 }
195 return familyList;
196}
197
198/* Converts from legacy Qt font weight (Qt < 6.0) to OpenType font weight (Qt >= 6.0) */
199Q_GUI_EXPORT int qt_legacyToOpenTypeWeight(int weight)
200{
201 return convertWeights(weight, false);
202}
203
204/* Converts from OpenType font weight (Qt >= 6.0) to legacy Qt font weight (Qt < 6.0) */
205Q_GUI_EXPORT int qt_openTypeToLegacyWeight(int weight)
206{
207 return convertWeights(weight, true);
208}
209
210QFontPrivate::QFontPrivate()
211 : engineData(nullptr), dpi(qt_defaultDpi()),
212 underline(false), overline(false), strikeOut(false), kerning(true),
213 capital(0), letterSpacingIsAbsolute(false), scFont(nullptr)
214{
215}
216
217QFontPrivate::QFontPrivate(const QFontPrivate &other)
218 : request(other.request), engineData(nullptr), dpi(other.dpi),
219 underline(other.underline), overline(other.overline),
220 strikeOut(other.strikeOut), kerning(other.kerning),
221 capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
222 letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
223 features(other.features), scFont(other.scFont)
224{
225 if (scFont && scFont != this)
226 scFont->ref.ref();
227}
228
229QFontPrivate::~QFontPrivate()
230{
231 if (engineData && !engineData->ref.deref())
232 delete engineData;
233 engineData = nullptr;
234 if (scFont && scFont != this) {
235 if (!scFont->ref.deref())
236 delete scFont;
237 }
238 scFont = nullptr;
239}
240
242
243#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script]
244
245QFontEngine *QFontPrivate::engineForScript(int script) const
246{
247 QMutexLocker locker(qt_fontdatabase_mutex());
248 if (script <= QChar::Script_Latin)
249 script = QChar::Script_Common;
250 if (engineData && engineData->fontCacheId != QFontCache::instance()->id()) {
251 // throw out engineData that came from a different thread
252 if (!engineData->ref.deref())
253 delete engineData;
254 engineData = nullptr;
255 }
256 if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script))
257 QFontDatabasePrivate::load(this, script);
258 return QT_FONT_ENGINE_FROM_DATA(engineData, script);
259}
260
261QFontEngine *QFontPrivate::engineForCharacter(char32_t c, EngineQueryOptions opt) const
262{
263 const bool smallCaps = !(opt & EngineQueryOption::IgnoreSmallCapsEngine);
264 const auto script = QChar::script(c);
265 QFontEngine *engine;
266 if (smallCaps && capital == QFont::SmallCaps && QChar::isLower(c))
267 engine = smallCapsFontPrivate()->engineForScript(script);
268 else
269 engine = engineForScript(script);
270 Q_ASSERT(engine != nullptr);
271 return engine;
272}
273
274void QFontPrivate::alterCharForCapitalization(QChar &c) const {
275 switch (capital) {
276 case QFont::AllUppercase:
277 case QFont::SmallCaps:
278 c = c.toUpper();
279 break;
280 case QFont::AllLowercase:
281 c = c.toLower();
282 break;
283 case QFont::MixedCase:
284 break;
285 }
286}
287
288QFontPrivate *QFontPrivate::smallCapsFontPrivate() const
289{
290 if (scFont)
291 return scFont;
292 QFont font(const_cast<QFontPrivate *>(this));
293 qreal pointSize = font.pointSizeF();
294 if (pointSize > 0)
295 font.setPointSizeF(pointSize * .7);
296 else
297 font.setPixelSize((font.pixelSize() * 7 + 5) / 10);
298 scFont = font.d.data();
299 if (scFont != this)
300 scFont->ref.ref();
301 return scFont;
302}
303
304
305void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
306{
307 Q_ASSERT(other != nullptr);
308
309 dpi = other->dpi;
310
311 if ((mask & QFont::AllPropertiesResolved) == QFont::AllPropertiesResolved) return;
312
313 // assign the unset-bits with the set-bits of the other font def
314 if (!(mask & QFont::FamiliesResolved))
315 request.families = other->request.families;
316
317 if (! (mask & QFont::StyleNameResolved))
318 request.styleName = other->request.styleName;
319
320 if (! (mask & QFont::SizeResolved)) {
321 request.pointSize = other->request.pointSize;
322 request.pixelSize = other->request.pixelSize;
323 }
324
325 if (! (mask & QFont::StyleHintResolved))
326 request.styleHint = other->request.styleHint;
327
328 if (! (mask & QFont::StyleStrategyResolved))
329 request.styleStrategy = other->request.styleStrategy;
330
331 if (! (mask & QFont::WeightResolved))
332 request.weight = other->request.weight;
333
334 if (! (mask & QFont::StyleResolved))
335 request.style = other->request.style;
336
337 if (! (mask & QFont::FixedPitchResolved))
338 request.fixedPitch = other->request.fixedPitch;
339
340 if (! (mask & QFont::StretchResolved))
341 request.stretch = other->request.stretch;
342
343 if (! (mask & QFont::HintingPreferenceResolved))
344 request.hintingPreference = other->request.hintingPreference;
345
346 if (! (mask & QFont::UnderlineResolved))
347 underline = other->underline;
348
349 if (! (mask & QFont::OverlineResolved))
350 overline = other->overline;
351
352 if (! (mask & QFont::StrikeOutResolved))
353 strikeOut = other->strikeOut;
354
355 if (! (mask & QFont::KerningResolved))
356 kerning = other->kerning;
357
358 if (! (mask & QFont::LetterSpacingResolved)) {
359 letterSpacing = other->letterSpacing;
360 letterSpacingIsAbsolute = other->letterSpacingIsAbsolute;
361 }
362 if (! (mask & QFont::WordSpacingResolved))
363 wordSpacing = other->wordSpacing;
364 if (! (mask & QFont::CapitalizationResolved))
365 capital = other->capital;
366
367 if (!(mask & QFont::FeaturesResolved))
368 features = other->features;
369
370 if (!(mask & QFont::VariableAxesResolved))
371 request.variableAxisValues = other->request.variableAxisValues;
372}
373
374bool QFontPrivate::hasVariableAxis(QFont::Tag tag, float value) const
375{
376 return request.variableAxisValues.contains(tag) && request.variableAxisValues.value(tag) == value;
377}
378
379void QFontPrivate::setVariableAxis(QFont::Tag tag, float value)
380{
381 request.variableAxisValues.insert(tag, value);
382}
383
384void QFontPrivate::unsetVariableAxis(QFont::Tag tag)
385{
386 request.variableAxisValues.remove(tag);
387}
388
389void QFontPrivate::setFeature(QFont::Tag tag, quint32 value)
390{
391 features.insert(tag, value);
392}
393
394void QFontPrivate::unsetFeature(QFont::Tag tag)
395{
396 features.remove(tag);
397}
398
399
402{
403 memset(engines, 0, QFontDatabasePrivate::ScriptCount * sizeof(QFontEngine *));
404}
405
407{
408 Q_ASSERT(ref.loadRelaxed() == 0);
409 for (int i = 0; i < QFontDatabasePrivate::ScriptCount; ++i) {
410 if (engines[i]) {
411 if (!engines[i]->ref.deref())
412 delete engines[i];
413 engines[i] = nullptr;
414 }
415 }
416}
417
418
419
420
421/*!
422 \class QFont
423 \reentrant
424
425 \brief The QFont class specifies a query for a font used for drawing text.
426
427 \ingroup painting
428 \ingroup appearance
429 \ingroup shared
430 \ingroup richtext-processing
431 \inmodule QtGui
432
433 QFont can be regarded as a query for one or more fonts on the system.
434
435 When you create a QFont object you specify various attributes that
436 you want the font to have. Qt will use the font with the specified
437 attributes, or if no matching font exists, Qt will use the closest
438 matching installed font. The attributes of the font that is
439 actually used are retrievable from a QFontInfo object. If the
440 window system provides an exact match exactMatch() returns \c true.
441 Use QFontMetricsF to get measurements, e.g. the pixel length of a
442 string using QFontMetrics::horizontalAdvance().
443
444 Attributes which are not specifically set will not affect the font
445 selection algorithm, and default values will be preferred instead.
446
447 To load a specific physical font, typically represented by a single file,
448 use QRawFont instead.
449
450 Note that a QGuiApplication instance must exist before a QFont can be
451 used. You can set the application's default font with
452 QGuiApplication::setFont().
453
454 If a chosen font does not include all the characters that
455 need to be displayed, QFont will try to find the characters in the
456 nearest equivalent fonts. When a QPainter draws a character from a
457 font the QFont will report whether or not it has the character; if
458 it does not, QPainter will draw an unfilled square.
459
460 Create QFonts like this:
461
462 \snippet code/src_gui_text_qfont.cpp 0
463
464 The attributes set in the constructor can also be set later, e.g.
465 setFamily(), setPointSize(), setPointSizeF(), setWeight() and
466 setItalic(). The remaining attributes must be set after
467 construction, e.g. setBold(), setUnderline(), setOverline(),
468 setStrikeOut() and setFixedPitch(). QFontInfo objects should be
469 created \e after the font's attributes have been set. A QFontInfo
470 object will not change, even if you change the font's
471 attributes. The corresponding "get" functions, e.g. family(),
472 pointSize(), etc., return the values that were set, even though
473 the values used may differ. The actual values are available from a
474 QFontInfo object.
475
476 If the requested font family is unavailable you can influence the
477 \l{#fontmatching}{font matching algorithm} by choosing a
478 particular \l{QFont::StyleHint} and \l{QFont::StyleStrategy} with
479 setStyleHint(). The default family (corresponding to the current
480 style hint) is returned by defaultFamily().
481
482 You can provide substitutions for font family names using
483 insertSubstitution() and insertSubstitutions(). Substitutions can
484 be removed with removeSubstitutions(). Use substitute() to retrieve
485 a family's first substitute, or the family name itself if it has
486 no substitutes. Use substitutes() to retrieve a list of a family's
487 substitutes (which may be empty). After substituting a font, you must
488 trigger the updating of the font by destroying and re-creating all
489 QFont objects.
490
491 Every QFont has a key() which you can use, for example, as the key
492 in a cache or dictionary. If you want to store a user's font
493 preferences you could use QSettings, writing the font information
494 with toString() and reading it back with fromString(). The
495 operator<<() and operator>>() functions are also available, but
496 they work on a data stream.
497
498 It is possible to set the height of characters shown on the screen
499 to a specified number of pixels with setPixelSize(); however using
500 setPointSize() has a similar effect and provides device
501 independence.
502
503 Loading fonts can be expensive, especially on X11. QFont contains
504 extensive optimizations to make the copying of QFont objects fast,
505 and to cache the results of the slow window system functions it
506 depends upon.
507
508 \target fontmatching
509 The font matching algorithm works as follows:
510 \list 1
511 \li The specified font families (set by setFamilies()) are searched for.
512 \li If not, a replacement font that supports the writing system is
513 selected. The font matching algorithm will try to find the
514 best match for all the properties set in the QFont. How this is
515 done varies from platform to platform.
516 \li If no font exists on the system that can support the text,
517 then special "missing character" boxes will be shown in its place.
518 \endlist
519
520 \note If the selected font, though supporting the writing system in general,
521 is missing glyphs for one or more specific characters, then Qt will try to
522 find a fallback font for this or these particular characters. This feature
523 can be disabled using QFont::NoFontMerging style strategy.
524
525 In Windows a request for the "Courier" font is automatically changed to
526 "Courier New", an improved version of Courier that allows for smooth scaling.
527 The older "Courier" bitmap font can be selected by setting the PreferBitmap
528 style strategy (see setStyleStrategy()).
529
530 Once a font is found, the remaining attributes are matched in order of
531 priority:
532 \list 1
533 \li fixedPitch()
534 \li pointSize() (see below)
535 \li weight()
536 \li style()
537 \endlist
538
539 If you have a font which matches on family, even if none of the
540 other attributes match, this font will be chosen in preference to
541 a font which doesn't match on family but which does match on the
542 other attributes. This is because font family is the dominant
543 search criteria.
544
545 The point size is defined to match if it is within 20% of the
546 requested point size. When several fonts match and are only
547 distinguished by point size, the font with the closest point size
548 to the one requested will be chosen.
549
550 The actual family, font size, weight and other font attributes
551 used for drawing text will depend on what's available for the
552 chosen family under the window system. A QFontInfo object can be
553 used to determine the actual values used for drawing the text.
554
555 Examples:
556
557 \snippet code/src_gui_text_qfont.cpp 1
558 If you had both an Adobe and a Cronyx Helvetica, you might get
559 either.
560
561 \snippet code/src_gui_text_qfont.cpp 2
562
563 You can specify the foundry you want in the family name. The font f
564 in the above example will be set to "Helvetica
565 [Cronyx]".
566
567 To determine the attributes of the font actually used in the window
568 system, use a QFontInfo object, e.g.
569
570 \snippet code/src_gui_text_qfont.cpp 3
571
572 To find out font metrics use a QFontMetrics object, e.g.
573
574 \snippet code/src_gui_text_qfont.cpp 4
575
576 For more general information on fonts, see the
577 \l{comp.fonts FAQ}{comp.fonts FAQ}.
578 Information on encodings can be found from the
579 \l{UTR17} page.
580
581 \sa QFontMetrics, QFontInfo, QFontDatabase
582*/
583
584/*!
585 \internal
586 \enum QFont::ResolveProperties
587
588 This enum describes the properties of a QFont that can be set on a font
589 individually and then considered resolved.
590
591 \value FamilyResolved
592 \value FamiliesResolved
593 \value SizeResolved
594 \value StyleHintResolved
595 \value StyleStrategyResolved
596 \value WeightResolved
597 \value StyleResolved
598 \value UnderlineResolved
599 \value OverlineResolved
600 \value StrikeOutResolved
601 \value FixedPitchResolved
602 \value StretchResolved
603 \value KerningResolved
604 \value CapitalizationResolved
605 \value LetterSpacingResolved
606 \value WordSpacingResolved
607 \value CompletelyResolved
608*/
609
610/*!
611 \enum QFont::Style
612
613 This enum describes the different styles of glyphs that are used to
614 display text.
615
616 \value StyleNormal Normal glyphs used in unstyled text.
617 \value StyleItalic Italic glyphs that are specifically designed for
618 the purpose of representing italicized text.
619 \value StyleOblique Glyphs with an italic appearance that are typically
620 based on the unstyled glyphs, but are not fine-tuned
621 for the purpose of representing italicized text.
622
623 \sa Weight
624*/
625
626/*!
627 \fn QFont &QFont::operator=(QFont &&other)
628
629 Move-assigns \a other to this QFont instance.
630
631 \since 5.2
632*/
633
634/*!
635 \since 5.13
636 Constructs a font from \a font for use on the paint device \a pd.
637*/
638QFont::QFont(const QFont &font, const QPaintDevice *pd)
639 : resolve_mask(font.resolve_mask)
640{
641 Q_ASSERT(pd);
642 const int dpi = pd->logicalDpiY();
643 if (font.d->dpi != dpi) {
644 d = new QFontPrivate(*font.d);
645 d->dpi = dpi;
646 } else {
647 d = font.d;
648 }
649}
650
651/*!
652 \internal
653*/
654QFont::QFont(QFontPrivate *data)
655 : d(data), resolve_mask(QFont::AllPropertiesResolved)
656{
657}
658
659/*! \internal
660 Detaches the font object from common font data.
661*/
662void QFont::detach()
663{
664 if (d->ref.loadRelaxed() == 1) {
665 if (d->engineData && !d->engineData->ref.deref())
666 delete d->engineData;
667 d->engineData = nullptr;
668 if (d->scFont && d->scFont != d.data()) {
669 if (!d->scFont->ref.deref())
670 delete d->scFont;
671 }
672 d->scFont = nullptr;
673 return;
674 }
675
676 d.detach();
677}
678
679/*!
680 \internal
681 Detaches the font object from common font attributes data.
682 Call this instead of QFont::detach() if the only font attributes data
683 has been changed (underline, letterSpacing, kerning, etc.).
684*/
685void QFontPrivate::detachButKeepEngineData(QFont *font)
686{
687 if (font->d->ref.loadRelaxed() == 1)
688 return;
689
690 QFontEngineData *engineData = font->d->engineData;
691 if (engineData)
692 engineData->ref.ref();
693 font->d.detach();
694 font->d->engineData = engineData;
695}
696
697/*!
698 Constructs a font object that uses the application's default font.
699
700 \sa QGuiApplication::setFont(), QGuiApplication::font()
701*/
702QFont::QFont()
703 : d(QGuiApplicationPrivate::instance() ? QGuiApplication::font().d.data() : new QFontPrivate()), resolve_mask(0)
704{
705}
706
707/*!
708 Constructs a font object with the specified \a family, \a
709 pointSize, \a weight and \a italic settings.
710
711 If \a pointSize is zero or negative, the point size of the font
712 is set to a system-dependent default value. Generally, this is
713 12 points.
714
715 The \a family name may optionally also include a foundry name,
716 e.g. "Helvetica [Cronyx]". If the \a family is
717 available from more than one foundry and the foundry isn't
718 specified, an arbitrary foundry is chosen. If the family isn't
719 available a family will be set using the \l{QFont}{font matching}
720 algorithm.
721
722 This will split the family string on a comma and call setFamilies() with the
723 resulting list. To preserve a font that uses a comma in its name, use
724 the constructor that takes a QStringList.
725
726 \sa Weight, setFamily(), setPointSize(), setWeight(), setItalic(),
727 setStyleHint(), setFamilies(), QGuiApplication::font()
728*/
729QFont::QFont(const QString &family, int pointSize, int weight, bool italic)
730 : d(new QFontPrivate()), resolve_mask(QFont::FamiliesResolved)
731{
732 if (pointSize <= 0) {
733 pointSize = 12;
734 } else {
735 resolve_mask |= QFont::SizeResolved;
736 }
737
738 if (weight < 0) {
739 weight = Normal;
740 } else {
741 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
742 }
743
744 if (italic)
745 resolve_mask |= QFont::StyleResolved;
746
747 d->request.families = splitIntoFamilies(family);
748 d->request.pointSize = qreal(pointSize);
749 d->request.pixelSize = -1;
750 d->request.weight = weight;
751 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
752}
753
754/*!
755 Constructs a font object with the specified \a families, \a
756 pointSize, \a weight and \a italic settings.
757
758 If \a pointSize is zero or negative, the point size of the font
759 is set to a system-dependent default value. Generally, this is
760 12 points.
761
762 Each family name entry in \a families may optionally also include
763 a foundry name, e.g. "Helvetica [Cronyx]". If the family is
764 available from more than one foundry and the foundry isn't
765 specified, an arbitrary foundry is chosen. If the family isn't
766 available a family will be set using the \l{QFont}{font matching}
767 algorithm.
768
769 \sa Weight, setPointSize(), setWeight(), setItalic(),
770 setStyleHint(), setFamilies(), QGuiApplication::font()
771 */
772QFont::QFont(const QStringList &families, int pointSize, int weight, bool italic)
773 : d(new QFontPrivate()), resolve_mask(QFont::FamiliesResolved)
774{
775 if (pointSize <= 0)
776 pointSize = 12;
777 else
778 resolve_mask |= QFont::SizeResolved;
779
780 if (weight < 0)
781 weight = Normal;
782 else
783 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
784
785 if (italic)
786 resolve_mask |= QFont::StyleResolved;
787
788 d->request.families = families;
789 d->request.pointSize = qreal(pointSize);
790 d->request.pixelSize = -1;
791 d->request.weight = weight;
792 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
793}
794
795/*!
796 Constructs a font that is a copy of \a font.
797*/
798QFont::QFont(const QFont &font)
799 : d(font.d), resolve_mask(font.resolve_mask)
800{
801}
802
803/*!
804 Destroys the font object and frees all allocated resources.
805*/
806QFont::~QFont()
807{
808}
809
810/*!
811 Assigns \a font to this font and returns a reference to it.
812*/
813QFont &QFont::operator=(const QFont &font)
814{
815 d = font.d;
816 resolve_mask = font.resolve_mask;
817 return *this;
818}
819
820/*!
821 \fn void QFont::swap(QFont &other)
822 \since 5.0
823 \memberswap{font instance}
824*/
825
826/*!
827 Returns the requested font family name. This will always be the same
828 as the first entry in the families() call.
829
830 \sa setFamily(), substitutes(), substitute(), setFamilies(), families()
831*/
832QString QFont::family() const
833{
834 return d->request.families.isEmpty() ? QString() : d->request.families.constFirst();
835}
836
837/*!
838 Sets the family name of the font. The name is case insensitive and
839 may include a foundry name.
840
841 The \a family name may optionally also include a foundry name,
842 e.g. "Helvetica [Cronyx]". If the \a family is
843 available from more than one foundry and the foundry isn't
844 specified, an arbitrary foundry is chosen. If the family isn't
845 available a family will be set using the \l{QFont}{font matching}
846 algorithm.
847
848 \sa family(), setStyleHint(), setFamilies(), families(), QFontInfo
849*/
850void QFont::setFamily(const QString &family)
851{
852 setFamilies(QStringList(family));
853}
854
855/*!
856 \since 4.8
857
858 Returns the requested font style name. This can be used to match the
859 font with irregular styles (that can't be normalized in other style
860 properties).
861
862 \sa setFamily(), setStyle()
863*/
864QString QFont::styleName() const
865{
866 return d->request.styleName;
867}
868
869/*!
870 \since 4.8
871
872 Sets the style name of the font to \a styleName. When set, other style properties
873 like \l style() and \l weight() will be ignored for font matching, though they may be
874 simulated afterwards if supported by the platform's font engine.
875
876 Due to the lower quality of artificially simulated styles, and the lack of full cross
877 platform support, it is not recommended to use matching by style name together with
878 matching by style properties
879
880 \sa styleName()
881*/
882void QFont::setStyleName(const QString &styleName)
883{
884 if ((resolve_mask & QFont::StyleNameResolved) && d->request.styleName == styleName)
885 return;
886
887 detach();
888
889 d->request.styleName = styleName;
890 resolve_mask |= QFont::StyleNameResolved;
891}
892
893/*!
894 Returns the point size of the font. Returns -1 if the font size
895 was specified in pixels.
896
897 \sa setPointSize(), pointSizeF()
898*/
899int QFont::pointSize() const
900{
901 return qRound(d->request.pointSize);
902}
903
904/*!
905 \since 4.8
906
907 \enum QFont::HintingPreference
908
909 This enum describes the different levels of hinting that can be applied
910 to glyphs to improve legibility on displays where it might be warranted
911 by the density of pixels.
912
913 \value PreferDefaultHinting Use the default hinting level for the target platform.
914 \value PreferNoHinting If possible, render text without hinting the outlines
915 of the glyphs. The text layout will be typographically accurate and
916 scalable, using the same metrics as are used e.g. when printing.
917 \value PreferVerticalHinting If possible, render text with no horizontal hinting,
918 but align glyphs to the pixel grid in the vertical direction. The text will appear
919 crisper on displays where the density is too low to give an accurate rendering
920 of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's
921 layout will be scalable to higher density devices (such as printers) without impacting
922 details such as line breaks.
923 \value PreferFullHinting If possible, render text with hinting in both horizontal and
924 vertical directions. The text will be altered to optimize legibility on the target
925 device, but since the metrics will depend on the target size of the text, the positions
926 of glyphs, line breaks, and other typographical detail will not scale, meaning that a
927 text layout may look different on devices with different pixel densities.
928
929 Please note that this enum only describes a preference, as the full range of hinting levels
930 are not supported on all of Qt's supported platforms. The following table details the effect
931 of a given hinting preference on a selected set of target platforms.
932
933 \table
934 \header
935 \li
936 \li PreferDefaultHinting
937 \li PreferNoHinting
938 \li PreferVerticalHinting
939 \li PreferFullHinting
940 \row
941 \li Windows and DirectWrite enabled in Qt
942 \li Full hinting
943 \li Vertical hinting
944 \li Vertical hinting
945 \li Full hinting
946 \row
947 \li FreeType
948 \li Operating System setting
949 \li No hinting
950 \li Vertical hinting (light)
951 \li Full hinting
952 \row
953 \li Cocoa on \macos
954 \li No hinting
955 \li No hinting
956 \li No hinting
957 \li No hinting
958 \endtable
959
960*/
961
962/*!
963 \since 4.8
964
965 Set the preference for the hinting level of the glyphs to \a hintingPreference. This is a hint
966 to the underlying font rendering system to use a certain level of hinting, and has varying
967 support across platforms. See the table in the documentation for QFont::HintingPreference for
968 more details.
969
970 The default hinting preference is QFont::PreferDefaultHinting.
971*/
972void QFont::setHintingPreference(HintingPreference hintingPreference)
973{
974 if ((resolve_mask & QFont::HintingPreferenceResolved) && d->request.hintingPreference == hintingPreference)
975 return;
976
977 detach();
978
979 d->request.hintingPreference = hintingPreference;
980
981 resolve_mask |= QFont::HintingPreferenceResolved;
982}
983
984/*!
985 \since 4.8
986
987 Returns the currently preferred hinting level for glyphs rendered with this font.
988*/
989QFont::HintingPreference QFont::hintingPreference() const
990{
991 return QFont::HintingPreference(d->request.hintingPreference);
992}
993
994/*!
995 Sets the point size to \a pointSize. The point size must be
996 greater than zero.
997
998 \sa pointSize(), setPointSizeF()
999*/
1000void QFont::setPointSize(int pointSize)
1001{
1002 if (pointSize <= 0) {
1003 qWarning("QFont::setPointSize: Point size <= 0 (%d), must be greater than 0", pointSize);
1004 return;
1005 }
1006
1007 if ((resolve_mask & QFont::SizeResolved) && d->request.pointSize == qreal(pointSize))
1008 return;
1009
1010 detach();
1011
1012 d->request.pointSize = qreal(pointSize);
1013 d->request.pixelSize = -1;
1014
1015 resolve_mask |= QFont::SizeResolved;
1016}
1017
1018/*!
1019 Sets the point size to \a pointSize. The point size must be
1020 greater than zero. The requested precision may not be achieved on
1021 all platforms.
1022
1023 \sa pointSizeF(), setPointSize(), setPixelSize()
1024*/
1025void QFont::setPointSizeF(qreal pointSize)
1026{
1027 if (pointSize <= 0) {
1028 qWarning("QFont::setPointSizeF: Point size <= 0 (%f), must be greater than 0", pointSize);
1029 return;
1030 }
1031
1032 if ((resolve_mask & QFont::SizeResolved) && d->request.pointSize == pointSize)
1033 return;
1034
1035 detach();
1036
1037 d->request.pointSize = pointSize;
1038 d->request.pixelSize = -1;
1039
1040 resolve_mask |= QFont::SizeResolved;
1041}
1042
1043/*!
1044 Returns the point size of the font. Returns -1 if the font size was
1045 specified in pixels.
1046
1047 \sa pointSize(), setPointSizeF(), pixelSize(), QFontInfo::pointSize(), QFontInfo::pixelSize()
1048*/
1049qreal QFont::pointSizeF() const
1050{
1051 return d->request.pointSize;
1052}
1053
1054/*!
1055 Sets the font size to \a pixelSize pixels, with a maxiumum size
1056 of an unsigned 16-bit integer.
1057
1058 Using this function makes the font device dependent. Use
1059 setPointSize() or setPointSizeF() to set the size of the font
1060 in a device independent manner.
1061
1062 \sa pixelSize()
1063*/
1064void QFont::setPixelSize(int pixelSize)
1065{
1066 if (pixelSize <= 0) {
1067 qWarning("QFont::setPixelSize: Pixel size <= 0 (%d)", pixelSize);
1068 return;
1069 }
1070
1071 if ((resolve_mask & QFont::SizeResolved) && d->request.pixelSize == qreal(pixelSize))
1072 return;
1073
1074 detach();
1075
1076 d->request.pixelSize = pixelSize;
1077 d->request.pointSize = -1;
1078
1079 resolve_mask |= QFont::SizeResolved;
1080}
1081
1082/*!
1083 Returns the pixel size of the font if it was set with
1084 setPixelSize(). Returns -1 if the size was set with setPointSize()
1085 or setPointSizeF().
1086
1087 \sa setPixelSize(), pointSize(), QFontInfo::pointSize(), QFontInfo::pixelSize()
1088*/
1089int QFont::pixelSize() const
1090{
1091 return d->request.pixelSize;
1092}
1093
1094/*!
1095 \fn bool QFont::italic() const
1096
1097 Returns \c true if the style() of the font is not QFont::StyleNormal
1098
1099 \sa setItalic(), style()
1100*/
1101
1102/*!
1103 \fn void QFont::setItalic(bool enable)
1104
1105 Sets the style() of the font to QFont::StyleItalic if \a enable is true;
1106 otherwise the style is set to QFont::StyleNormal.
1107
1108 \note If styleName() is set, this value may be ignored, or if supported
1109 on the platform, the font may be rendered tilted instead of picking a
1110 designed italic font-variant.
1111
1112 \sa italic(), QFontInfo
1113*/
1114
1115/*!
1116 Returns the style of the font.
1117
1118 \sa setStyle()
1119*/
1120QFont::Style QFont::style() const
1121{
1122 return (QFont::Style)d->request.style;
1123}
1124
1125
1126/*!
1127 Sets the style of the font to \a style.
1128
1129 \sa italic(), QFontInfo
1130*/
1131void QFont::setStyle(Style style)
1132{
1133 if ((resolve_mask & QFont::StyleResolved) && d->request.style == style)
1134 return;
1135
1136 detach();
1137
1138 d->request.style = style;
1139 resolve_mask |= QFont::StyleResolved;
1140}
1141
1142/*!
1143 Returns the weight of the font, using the same scale as the
1144 \l{QFont::Weight} enumeration.
1145
1146 \sa setWeight(), Weight, QFontInfo
1147*/
1148QFont::Weight QFont::weight() const
1149{
1150 return static_cast<Weight>(d->request.weight);
1151}
1152
1153/*!
1154 \enum QFont::Weight
1155
1156 Qt uses a weighting scale from 1 to 1000 compatible with OpenType. A weight of 1 will be
1157 thin, whilst 1000 will be extremely black.
1158
1159 This enum contains the predefined font weights:
1160
1161 \value Thin 100
1162 \value ExtraLight 200
1163 \value Light 300
1164 \value Normal 400
1165 \value Medium 500
1166 \value DemiBold 600
1167 \value Bold 700
1168 \value ExtraBold 800
1169 \value Black 900
1170*/
1171
1172#if QT_DEPRECATED_SINCE(6, 0)
1173/*!
1174 \deprecated [6.0] Use setWeight() instead.
1175
1176 Sets the weight of the font to \a legacyWeight using the legacy font
1177 weight scale of Qt 5 and previous versions.
1178
1179 Since Qt 6, the OpenType standard's font weight scale is used instead
1180 of a non-standard scale. This requires conversion from values that
1181 use the old scale. For convenience, this function may be used when
1182 porting from code which uses the old weight scale.
1183
1184 \note If styleName() is set, this value may be ignored for font selection.
1185
1186 \sa setWeight(), weight(), QFontInfo
1187*/
1188void QFont::setLegacyWeight(int legacyWeight)
1189{
1190 setWeight(QFont::Weight(qt_legacyToOpenTypeWeight(legacyWeight)));
1191}
1192
1193/*!
1194 \deprecated [6.0] Use weight() instead.
1195
1196 Returns the weight of the font converted to the non-standard font
1197 weight scale used in Qt 5 and earlier versions.
1198
1199 Since Qt 6, the OpenType standard's font weight scale is used instead
1200 of a non-standard scale. This requires conversion from values that
1201 use the old scale. For convenience, this function may be used when
1202 porting from code which uses the old weight scale.
1203
1204 \sa setWeight(), weight(), QFontInfo
1205*/
1206int QFont::legacyWeight() const
1207{
1208 return qt_openTypeToLegacyWeight(weight());
1209}
1210#endif // QT_DEPRECATED_SINCE(6, 0)
1211
1212/*!
1213 Sets the weight of the font to \a weight, using the scale defined by
1214 \l QFont::Weight enumeration.
1215
1216 \note If styleName() is set, this value may be ignored for font selection.
1217
1218 \sa weight(), QFontInfo
1219*/
1220void QFont::setWeight(QFont::Weight weight)
1221{
1222 const int weightValue = qBound(QFONT_WEIGHT_MIN, static_cast<int>(weight), QFONT_WEIGHT_MAX);
1223 if (weightValue != static_cast<int>(weight)) {
1224 qWarning() << "QFont::setWeight: Weight must be between 1 and 1000, attempted to set "
1225 << static_cast<int>(weight);
1226 }
1227
1228 if ((resolve_mask & QFont::WeightResolved) && d->request.weight == weightValue)
1229 return;
1230
1231 detach();
1232
1233 d->request.weight = weightValue;
1234 resolve_mask |= QFont::WeightResolved;
1235}
1236
1237/*!
1238 \fn bool QFont::bold() const
1239
1240 Returns \c true if weight() is a value greater than
1241 \l{Weight}{QFont::Medium}; otherwise returns \c false.
1242
1243 \sa weight(), setBold(), QFontInfo::bold()
1244*/
1245
1246/*!
1247 \fn void QFont::setBold(bool enable)
1248
1249 If \a enable is true sets the font's weight to
1250 \l{Weight}{QFont::Bold};
1251 otherwise sets the weight to \l{Weight}{QFont::Normal}.
1252
1253 For finer boldness control use setWeight().
1254
1255 \note If styleName() is set, this value may be ignored, or if supported
1256 on the platform, the font artificially embolded.
1257
1258 \sa bold(), setWeight()
1259*/
1260
1261/*!
1262 Returns \c true if underline has been set; otherwise returns \c false.
1263
1264 \sa setUnderline()
1265*/
1266bool QFont::underline() const
1267{
1268 return d->underline;
1269}
1270
1271/*!
1272 If \a enable is true, sets underline on; otherwise sets underline
1273 off.
1274
1275 \sa underline(), QFontInfo
1276*/
1277void QFont::setUnderline(bool enable)
1278{
1279 if ((resolve_mask & QFont::UnderlineResolved) && d->underline == enable)
1280 return;
1281
1282 QFontPrivate::detachButKeepEngineData(this);
1283
1284 d->underline = enable;
1285 resolve_mask |= QFont::UnderlineResolved;
1286}
1287
1288/*!
1289 Returns \c true if overline has been set; otherwise returns \c false.
1290
1291 \sa setOverline()
1292*/
1293bool QFont::overline() const
1294{
1295 return d->overline;
1296}
1297
1298/*!
1299 If \a enable is true, sets overline on; otherwise sets overline off.
1300
1301 \sa overline(), QFontInfo
1302*/
1303void QFont::setOverline(bool enable)
1304{
1305 if ((resolve_mask & QFont::OverlineResolved) && d->overline == enable)
1306 return;
1307
1308 QFontPrivate::detachButKeepEngineData(this);
1309
1310 d->overline = enable;
1311 resolve_mask |= QFont::OverlineResolved;
1312}
1313
1314/*!
1315 Returns \c true if strikeout has been set; otherwise returns \c false.
1316
1317 \sa setStrikeOut()
1318*/
1319bool QFont::strikeOut() const
1320{
1321 return d->strikeOut;
1322}
1323
1324/*!
1325 If \a enable is true, sets strikeout on; otherwise sets strikeout
1326 off.
1327
1328 \sa strikeOut(), QFontInfo
1329*/
1330void QFont::setStrikeOut(bool enable)
1331{
1332 if ((resolve_mask & QFont::StrikeOutResolved) && d->strikeOut == enable)
1333 return;
1334
1335 QFontPrivate::detachButKeepEngineData(this);
1336
1337 d->strikeOut = enable;
1338 resolve_mask |= QFont::StrikeOutResolved;
1339}
1340
1341/*!
1342 Returns \c true if fixed pitch has been set; otherwise returns \c false.
1343
1344 \sa setFixedPitch(), QFontInfo::fixedPitch()
1345*/
1346bool QFont::fixedPitch() const
1347{
1348 return d->request.fixedPitch;
1349}
1350
1351/*!
1352 If \a enable is true, sets fixed pitch on; otherwise sets fixed
1353 pitch off.
1354
1355 \sa fixedPitch(), QFontInfo
1356*/
1357void QFont::setFixedPitch(bool enable)
1358{
1359 if ((resolve_mask & QFont::FixedPitchResolved) && d->request.fixedPitch == enable)
1360 return;
1361
1362 detach();
1363
1364 d->request.fixedPitch = enable;
1365 d->request.ignorePitch = false;
1366 resolve_mask |= QFont::FixedPitchResolved;
1367}
1368
1369/*!
1370 Returns \c true if kerning should be used when drawing text with this font.
1371
1372 \sa setKerning()
1373*/
1374bool QFont::kerning() const
1375{
1376 return d->kerning;
1377}
1378
1379/*!
1380 Enables kerning for this font if \a enable is true; otherwise
1381 disables it. By default, kerning is enabled.
1382
1383 When kerning is enabled, glyph metrics do not add up anymore,
1384 even for Latin text. In other words, the assumption that
1385 width('a') + width('b') is equal to width("ab") is not
1386 necessarily true.
1387
1388 \sa kerning(), QFontMetrics
1389*/
1390void QFont::setKerning(bool enable)
1391{
1392 if ((resolve_mask & QFont::KerningResolved) && d->kerning == enable)
1393 return;
1394
1395 QFontPrivate::detachButKeepEngineData(this);
1396
1397 d->kerning = enable;
1398 resolve_mask |= QFont::KerningResolved;
1399}
1400
1401/*!
1402 Returns the StyleStrategy.
1403
1404 The style strategy affects the \l{QFont}{font matching} algorithm.
1405 See \l QFont::StyleStrategy for the list of available strategies.
1406
1407 \sa setStyleHint(), QFont::StyleHint
1408*/
1409QFont::StyleStrategy QFont::styleStrategy() const
1410{
1411 return (StyleStrategy) d->request.styleStrategy;
1412}
1413
1414/*!
1415 Returns the StyleHint.
1416
1417 The style hint affects the \l{QFont#fontmatching}{font matching algorithm}.
1418 See \l QFont::StyleHint for the list of available hints.
1419
1420 \sa setStyleHint(), QFont::StyleStrategy, QFontInfo::styleHint()
1421*/
1422QFont::StyleHint QFont::styleHint() const
1423{
1424 return (StyleHint) d->request.styleHint;
1425}
1426
1427/*!
1428 \enum QFont::StyleHint
1429
1430 Style hints are used by the \l{QFont}{font matching} algorithm to
1431 find an appropriate default family if a selected font family is
1432 not available.
1433
1434 \value AnyStyle leaves the font matching algorithm to choose the
1435 family. This is the default.
1436
1437 \value SansSerif the font matcher prefer sans serif fonts.
1438 \value Helvetica is a synonym for \c SansSerif.
1439
1440 \value Serif the font matcher prefers serif fonts.
1441 \value Times is a synonym for \c Serif.
1442
1443 \value TypeWriter the font matcher prefers fixed pitch fonts.
1444 \value Courier a synonym for \c TypeWriter.
1445
1446 \value OldEnglish the font matcher prefers decorative fonts.
1447 \value Decorative is a synonym for \c OldEnglish.
1448
1449 \value Monospace the font matcher prefers fonts that map to the
1450 CSS generic font-family 'monospace'.
1451
1452 \value Fantasy the font matcher prefers fonts that map to the
1453 CSS generic font-family 'fantasy'.
1454
1455 \value Cursive the font matcher prefers fonts that map to the
1456 CSS generic font-family 'cursive'.
1457
1458 \value System the font matcher prefers system fonts.
1459*/
1460
1461/*!
1462 \enum QFont::StyleStrategy
1463
1464 The style strategy tells the \l{QFont}{font matching} algorithm
1465 what type of fonts should be used to find an appropriate default
1466 family.
1467
1468 The following strategies are available:
1469
1470 \value PreferDefault the default style strategy. It does not prefer
1471 any type of font.
1472 \value PreferBitmap prefers bitmap fonts (as opposed to outline
1473 fonts).
1474 \value PreferDevice prefers device fonts.
1475 \value PreferOutline prefers outline fonts (as opposed to bitmap fonts).
1476 \value ForceOutline forces the use of outline fonts.
1477 \value NoAntialias don't antialias the fonts.
1478 \value NoSubpixelAntialias avoid subpixel antialiasing on the fonts if possible.
1479 \value PreferAntialias antialias if possible.
1480 \value [since 6.8] ContextFontMerging If the selected font does not contain a certain character,
1481 then Qt automatically chooses a similar-looking fallback font that contains the
1482 character. By default this is done on a character-by-character basis. This means that in
1483 certain uncommon cases, multiple fonts may be used to represent one string of text even
1484 if it's in the same script. Setting \c ContextFontMerging will try finding the fallback
1485 font that matches the largest subset of the input string instead. This will be more
1486 expensive for strings where missing glyphs occur, but may give more consistent results.
1487 If \c NoFontMerging is set, then \c ContextFontMerging will have no effect.
1488 \value [since 6.8] PreferTypoLineMetrics For compatibility reasons, OpenType fonts contain
1489 two competing sets of the vertical line metrics that provide the
1490 \l{QFontMetricsF::ascent()}{ascent}, \l{QFontMetricsF::descent()}{descent} and
1491 \l{QFontMetricsF::leading()}{leading} of the font. These are often referred to as the
1492 \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswinascent}{win}
1493 (Windows) metrics and the
1494 \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#sta}{typo}
1495 (typographical) metrics. While the specification recommends using the \c typo metrics for
1496 line spacing, many applications prefer the \c win metrics unless the \c{USE_TYPO_METRICS}
1497 flag is set in the
1498 \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection}{fsSelection}
1499 field of the font. For backwards-compatibility reasons, this is also the case for Qt
1500 applications. This is not an issue for fonts that set the \c{USE_TYPO_METRICS} flag to
1501 indicate that the \c{typo} metrics are valid, nor for fonts where the \c{win} metrics
1502 and \c{typo} metrics match up. However, for certain fonts the \c{win} metrics may be
1503 larger than the preferable line spacing and the \c{USE_TYPO_METRICS} flag may be unset
1504 by mistake. For such fonts, setting \c{PreferTypoLineMetrics} may give superior results.
1505 \value NoFontMerging If the font selected for a certain writing system
1506 does not contain a character requested to draw, then Qt automatically chooses a similar
1507 looking font that contains the character. The NoFontMerging flag disables this feature.
1508 Please note that enabling this flag will not prevent Qt from automatically picking a
1509 suitable font when the selected font does not support the writing system of the text.
1510 \value PreferNoShaping Sometimes, a font will apply complex rules to a set of characters in
1511 order to display them correctly. In some writing systems, such as Brahmic scripts, this is
1512 required in order for the text to be legible, but in e.g. Latin script, it is merely
1513 a cosmetic feature. The PreferNoShaping flag will disable all such features when they
1514 are not required, which will improve performance in most cases (since Qt 5.10).
1515
1516 Any of these may be OR-ed with one of these flags:
1517
1518 \value PreferMatch prefer an exact match. The font matcher will try to
1519 use the exact font size that has been specified.
1520 \value PreferQuality prefer the best quality font. The font matcher
1521 will use the nearest standard point size that the font
1522 supports.
1523*/
1524
1525/*!
1526 Sets the style hint and strategy to \a hint and \a strategy,
1527 respectively.
1528
1529 If these aren't set explicitly the style hint will default to
1530 \c AnyStyle and the style strategy to \c PreferDefault.
1531
1532 Qt does not support style hints on X11 since this information
1533 is not provided by the window system.
1534
1535 \sa StyleHint, styleHint(), StyleStrategy, styleStrategy(), QFontInfo
1536*/
1537void QFont::setStyleHint(StyleHint hint, StyleStrategy strategy)
1538{
1539 if ((resolve_mask & (QFont::StyleHintResolved | QFont::StyleStrategyResolved)) &&
1540 (StyleHint) d->request.styleHint == hint &&
1541 (StyleStrategy) d->request.styleStrategy == strategy)
1542 return;
1543
1544 detach();
1545
1546 d->request.styleHint = hint;
1547 d->request.styleStrategy = strategy;
1548 resolve_mask |= QFont::StyleHintResolved;
1549 resolve_mask |= QFont::StyleStrategyResolved;
1550
1551}
1552
1553/*!
1554 Sets the style strategy for the font to \a s.
1555
1556 \sa QFont::StyleStrategy
1557*/
1558void QFont::setStyleStrategy(StyleStrategy s)
1559{
1560 if ((resolve_mask & QFont::StyleStrategyResolved) &&
1561 s == (StyleStrategy)d->request.styleStrategy)
1562 return;
1563
1564 detach();
1565
1566 d->request.styleStrategy = s;
1567 resolve_mask |= QFont::StyleStrategyResolved;
1568}
1569
1570
1571/*!
1572 \enum QFont::Stretch
1573
1574 Predefined stretch values that follow the CSS naming convention. The higher
1575 the value, the more stretched the text is.
1576
1577 \value [since 5.8] AnyStretch 0 Accept any stretch matched using the other QFont properties
1578 \value UltraCondensed 50
1579 \value ExtraCondensed 62
1580 \value Condensed 75
1581 \value SemiCondensed 87
1582 \value Unstretched 100
1583 \value SemiExpanded 112
1584 \value Expanded 125
1585 \value ExtraExpanded 150
1586 \value UltraExpanded 200
1587
1588 \sa setStretch(), stretch()
1589*/
1590
1591/*!
1592 Returns the stretch factor for the font.
1593
1594 \sa setStretch()
1595 */
1596int QFont::stretch() const
1597{
1598 return d->request.stretch;
1599}
1600
1601/*!
1602 Sets the stretch factor for the font.
1603
1604 The stretch factor matches a condensed or expanded version of the font or
1605 applies a stretch transform that changes the width of all characters
1606 in the font by \a factor percent. For example, setting \a factor to 150
1607 results in all characters in the font being 1.5 times (ie. 150%)
1608 wider. The minimum stretch factor is 1, and the maximum stretch factor
1609 is 4000. The default stretch factor is \c AnyStretch, which will accept
1610 any stretch factor and not apply any transform on the font.
1611
1612 The stretch factor is only applied to outline fonts. The stretch
1613 factor is ignored for bitmap fonts.
1614
1615 \note When matching a font with a native non-default stretch factor,
1616 requesting a stretch of 100 will stretch it back to a medium width font.
1617
1618 \sa stretch(), QFont::Stretch
1619*/
1620void QFont::setStretch(int factor)
1621{
1622 if (factor < 0 || factor > 4000) {
1623 qWarning("QFont::setStretch: Parameter '%d' out of range", factor);
1624 return;
1625 }
1626
1627 if ((resolve_mask & QFont::StretchResolved) &&
1628 d->request.stretch == (uint)factor)
1629 return;
1630
1631 detach();
1632
1633 d->request.stretch = (uint)factor;
1634 resolve_mask |= QFont::StretchResolved;
1635}
1636
1637/*!
1638 \enum QFont::SpacingType
1639 \since 4.4
1640
1641 \value PercentageSpacing A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the
1642 spacing after a character by the width of the character itself.
1643 \value AbsoluteSpacing A positive value increases the letter spacing by the corresponding pixels; a negative
1644 value decreases the spacing.
1645*/
1646
1647/*!
1648 \since 4.4
1649 Returns the letter spacing for the font.
1650
1651 \sa setLetterSpacing(), letterSpacingType(), setWordSpacing()
1652 */
1653qreal QFont::letterSpacing() const
1654{
1655 return d->letterSpacing.toReal();
1656}
1657
1658/*!
1659 \since 4.4
1660 Sets the letter spacing for the font to \a spacing and the type
1661 of spacing to \a type.
1662
1663 Letter spacing changes the default spacing between individual
1664 letters in the font. The spacing between the letters can be
1665 made smaller as well as larger either in percentage of the
1666 character width or in pixels, depending on the selected spacing type.
1667
1668 \sa letterSpacing(), letterSpacingType(), setWordSpacing()
1669*/
1670void QFont::setLetterSpacing(SpacingType type, qreal spacing)
1671{
1672 const QFixed newSpacing = QFixed::fromReal(spacing);
1673 const bool absoluteSpacing = type == AbsoluteSpacing;
1674 if ((resolve_mask & QFont::LetterSpacingResolved) &&
1675 d->letterSpacingIsAbsolute == absoluteSpacing &&
1676 d->letterSpacing == newSpacing)
1677 return;
1678
1679 QFontPrivate::detachButKeepEngineData(this);
1680
1681 d->letterSpacing = newSpacing;
1682 d->letterSpacingIsAbsolute = absoluteSpacing;
1683 resolve_mask |= QFont::LetterSpacingResolved;
1684}
1685
1686/*!
1687 \since 4.4
1688 Returns the spacing type used for letter spacing.
1689
1690 \sa letterSpacing(), setLetterSpacing(), setWordSpacing()
1691*/
1692QFont::SpacingType QFont::letterSpacingType() const
1693{
1694 return d->letterSpacingIsAbsolute ? AbsoluteSpacing : PercentageSpacing;
1695}
1696
1697/*!
1698 \since 4.4
1699 Returns the word spacing for the font.
1700
1701 \sa setWordSpacing(), setLetterSpacing()
1702 */
1703qreal QFont::wordSpacing() const
1704{
1705 return d->wordSpacing.toReal();
1706}
1707
1708/*!
1709 \since 4.4
1710 Sets the word spacing for the font to \a spacing.
1711
1712 Word spacing changes the default spacing between individual
1713 words. A positive value increases the word spacing
1714 by a corresponding amount of pixels, while a negative value
1715 decreases the inter-word spacing accordingly.
1716
1717 Word spacing will not apply to writing systems, where indiviaul
1718 words are not separated by white space.
1719
1720 \sa wordSpacing(), setLetterSpacing()
1721*/
1722void QFont::setWordSpacing(qreal spacing)
1723{
1724 const QFixed newSpacing = QFixed::fromReal(spacing);
1725 if ((resolve_mask & QFont::WordSpacingResolved) &&
1726 d->wordSpacing == newSpacing)
1727 return;
1728
1729 QFontPrivate::detachButKeepEngineData(this);
1730
1731 d->wordSpacing = newSpacing;
1732 resolve_mask |= QFont::WordSpacingResolved;
1733}
1734
1735/*!
1736 \enum QFont::Capitalization
1737 \since 4.4
1738
1739 Rendering option for text this font applies to.
1740
1741
1742 \value MixedCase This is the normal text rendering option where no capitalization change is applied.
1743 \value AllUppercase This alters the text to be rendered in all uppercase type.
1744 \value AllLowercase This alters the text to be rendered in all lowercase type.
1745 \value SmallCaps This alters the text to be rendered in small-caps type.
1746 \value Capitalize This alters the text to be rendered with the first character of each word as an uppercase character.
1747*/
1748
1749/*!
1750 \since 4.4
1751 Sets the capitalization of the text in this font to \a caps.
1752
1753 A font's capitalization makes the text appear in the selected capitalization mode.
1754
1755 \sa capitalization()
1756*/
1757void QFont::setCapitalization(Capitalization caps)
1758{
1759 if ((resolve_mask & QFont::CapitalizationResolved) &&
1760 capitalization() == caps)
1761 return;
1762
1763 QFontPrivate::detachButKeepEngineData(this);
1764
1765 d->capital = caps;
1766 resolve_mask |= QFont::CapitalizationResolved;
1767}
1768
1769/*!
1770 \since 4.4
1771 Returns the current capitalization type of the font.
1772
1773 \sa setCapitalization()
1774*/
1775QFont::Capitalization QFont::capitalization() const
1776{
1777 return static_cast<QFont::Capitalization> (d->capital);
1778}
1779
1780/*!
1781 Returns \c true if a window system font exactly matching the settings
1782 of this font is available.
1783
1784 \sa QFontInfo
1785*/
1786bool QFont::exactMatch() const
1787{
1788 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
1789 Q_ASSERT(engine != nullptr);
1790 return d->request.exactMatch(engine->fontDef);
1791}
1792
1793/*!
1794 Returns \c true if this font is equal to \a f; otherwise returns
1795 false.
1796
1797 Two QFonts are considered equal if their font attributes are
1798 equal.
1799
1800 \sa operator!=(), isCopyOf()
1801*/
1802bool QFont::operator==(const QFont &f) const
1803{
1804 return (f.d == d
1805 || (f.d->request == d->request
1806 && f.d->request.pointSize == d->request.pointSize
1807 && f.d->underline == d->underline
1808 && f.d->overline == d->overline
1809 && f.d->strikeOut == d->strikeOut
1810 && f.d->kerning == d->kerning
1811 && f.d->capital == d->capital
1812 && f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
1813 && f.d->letterSpacing == d->letterSpacing
1814 && f.d->wordSpacing == d->wordSpacing
1815 && f.d->features == d->features
1816 ));
1817}
1818
1819
1820/*!
1821 Provides an arbitrary comparison of this font and font \a f.
1822 All that is guaranteed is that the operator returns \c false if both
1823 fonts are equal and that (f1 < f2) == !(f2 < f1) if the fonts
1824 are not equal.
1825
1826 This function is useful in some circumstances, for example if you
1827 want to use QFont objects as keys in a QMap.
1828
1829 \sa operator==(), operator!=(), isCopyOf()
1830*/
1831bool QFont::operator<(const QFont &f) const
1832{
1833 // NB: This operator actually implements greater-than, because it consistently
1834 // swaps LHS (should be *this, but is `f`) and RHS (should be `f`, but is *this)
1835 if (f.d == d) return false;
1836 // the < operator for fontdefs ignores point sizes.
1837 const QFontDef &r1 = f.d->request;
1838 const QFontDef &r2 = d->request;
1839 if (r1.pointSize != r2.pointSize) return r1.pointSize < r2.pointSize;
1840 if (r1.pixelSize != r2.pixelSize) return r1.pixelSize < r2.pixelSize;
1841 if (r1.weight != r2.weight) return r1.weight < r2.weight;
1842 if (r1.style != r2.style) return r1.style < r2.style;
1843 if (r1.stretch != r2.stretch) return r1.stretch < r2.stretch;
1844 if (r1.styleHint != r2.styleHint) return r1.styleHint < r2.styleHint;
1845 if (r1.styleStrategy != r2.styleStrategy) return r1.styleStrategy < r2.styleStrategy;
1846 if (r1.families != r2.families) return r1.families < r2.families;
1847 if (f.d->capital != d->capital) return f.d->capital < d->capital;
1848
1849 if (f.d->letterSpacingIsAbsolute != d->letterSpacingIsAbsolute) return f.d->letterSpacingIsAbsolute < d->letterSpacingIsAbsolute;
1850 if (f.d->letterSpacing != d->letterSpacing) return f.d->letterSpacing < d->letterSpacing;
1851 if (f.d->wordSpacing != d->wordSpacing) return f.d->wordSpacing < d->wordSpacing;
1852
1853 int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
1854 int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
1855 if (f1attrs != f2attrs) return f1attrs < f2attrs;
1856
1857 if (d->features != f.d->features) {
1858 return std::lexicographical_compare(f.d->features.keyValueBegin(), f.d->features.keyValueEnd(),
1859 d->features.keyValueBegin(), d->features.keyValueEnd());
1860 }
1861
1862 return std::lexicographical_compare(r1.variableAxisValues.keyValueBegin(), r1.variableAxisValues.keyValueEnd(),
1863 r2.variableAxisValues.keyValueBegin(), r2.variableAxisValues.keyValueEnd());
1864}
1865
1866
1867/*!
1868 Returns \c true if this font is different from \a f; otherwise
1869 returns \c false.
1870
1871 Two QFonts are considered to be different if their font attributes
1872 are different.
1873
1874 \sa operator==()
1875*/
1876bool QFont::operator!=(const QFont &f) const
1877{
1878 return !(operator==(f));
1879}
1880
1881/*!
1882 Returns the font as a QVariant
1883*/
1884QFont::operator QVariant() const
1885{
1886 return QVariant::fromValue(*this);
1887}
1888
1889/*!
1890 Returns \c true if this font and \a f are copies of each other, i.e.
1891 one of them was created as a copy of the other and neither has
1892 been modified since. This is much stricter than equality.
1893
1894 \sa operator=(), operator==()
1895*/
1896bool QFont::isCopyOf(const QFont & f) const
1897{
1898 return d == f.d;
1899}
1900
1901/*!
1902 Returns a new QFont that has attributes copied from \a other that
1903 have not been previously set on this font.
1904*/
1905QFont QFont::resolve(const QFont &other) const
1906{
1907 if (resolve_mask == 0 || (resolve_mask == other.resolve_mask && *this == other)) {
1908 QFont o(other);
1909 o.resolve_mask = resolve_mask;
1910 return o;
1911 }
1912
1913 QFont font(*this);
1914 font.detach();
1915 font.d->resolve(resolve_mask, other.d.data());
1916
1917 return font;
1918}
1919
1920/*!
1921 \fn uint QFont::resolveMask() const
1922 \internal
1923*/
1924
1925/*!
1926 \fn void QFont::setResolveMask(uint mask)
1927 \internal
1928*/
1929
1930
1931/*****************************************************************************
1932 QFont substitution management
1933 *****************************************************************************/
1934
1937
1938/*!
1939 Returns the first family name to be used whenever \a familyName is
1940 specified. The lookup is case insensitive.
1941
1942 If there is no substitution for \a familyName, \a familyName is
1943 returned.
1944
1945 To obtain a list of substitutions use substitutes().
1946
1947 \sa setFamily(), insertSubstitutions(), insertSubstitution(), removeSubstitutions()
1948*/
1949QString QFont::substitute(const QString &familyName)
1950{
1951 QFontSubst *fontSubst = globalFontSubst();
1952 Q_ASSERT(fontSubst != nullptr);
1953 QFontSubst::ConstIterator it = fontSubst->constFind(familyName.toLower());
1954 if (it != fontSubst->constEnd() && !(*it).isEmpty())
1955 return (*it).first();
1956
1957 return familyName;
1958}
1959
1960
1961/*!
1962 Returns a list of family names to be used whenever \a familyName
1963 is specified. The lookup is case insensitive.
1964
1965 If there is no substitution for \a familyName, an empty list is
1966 returned.
1967
1968 \sa substitute(), insertSubstitutions(), insertSubstitution(), removeSubstitutions()
1969 */
1970QStringList QFont::substitutes(const QString &familyName)
1971{
1972 QFontSubst *fontSubst = globalFontSubst();
1973 Q_ASSERT(fontSubst != nullptr);
1974 return fontSubst->value(familyName.toLower(), QStringList());
1975}
1976
1977
1978/*!
1979 Inserts \a substituteName into the substitution
1980 table for the family \a familyName.
1981
1982 After substituting a font, trigger the updating of the font by destroying
1983 and re-creating all QFont objects.
1984
1985 \sa insertSubstitutions(), removeSubstitutions(), substitutions(), substitute(), substitutes()
1986*/
1987void QFont::insertSubstitution(const QString &familyName,
1988 const QString &substituteName)
1989{
1990 QFontSubst *fontSubst = globalFontSubst();
1991 Q_ASSERT(fontSubst != nullptr);
1992 QStringList &list = (*fontSubst)[familyName.toLower()];
1993 QString s = substituteName.toLower();
1994 if (!list.contains(s))
1995 list.append(s);
1996}
1997
1998
1999/*!
2000 Inserts the list of families \a substituteNames into the
2001 substitution list for \a familyName.
2002
2003 After substituting a font, trigger the updating of the font by destroying
2004 and re-creating all QFont objects.
2005
2006
2007 \sa insertSubstitution(), removeSubstitutions(), substitutions(), substitute()
2008*/
2009void QFont::insertSubstitutions(const QString &familyName,
2010 const QStringList &substituteNames)
2011{
2012 QFontSubst *fontSubst = globalFontSubst();
2013 Q_ASSERT(fontSubst != nullptr);
2014 QStringList &list = (*fontSubst)[familyName.toLower()];
2015 for (const QString &substituteName : substituteNames) {
2016 const QString lowerSubstituteName = substituteName.toLower();
2017 if (!list.contains(lowerSubstituteName))
2018 list.append(lowerSubstituteName);
2019 }
2020}
2021
2022/*!
2023 Removes all the substitutions for \a familyName.
2024
2025 \sa insertSubstitutions(), insertSubstitution(), substitutions(), substitute()
2026 \since 5.0
2027*/
2028void QFont::removeSubstitutions(const QString &familyName)
2029{
2030 QFontSubst *fontSubst = globalFontSubst();
2031 Q_ASSERT(fontSubst != nullptr);
2032 fontSubst->remove(familyName.toLower());
2033}
2034
2035/*!
2036 Returns a sorted list of substituted family names.
2037
2038 \sa insertSubstitution(), removeSubstitutions(), substitute()
2039*/
2040QStringList QFont::substitutions()
2041{
2042 QFontSubst *fontSubst = globalFontSubst();
2043 Q_ASSERT(fontSubst != nullptr);
2044 QStringList ret = fontSubst->keys();
2045
2046 ret.sort();
2047 return ret;
2048}
2049
2050#ifndef QT_NO_DATASTREAM
2051/* \internal
2052 Internal function. Converts boolean font settings to an unsigned
2053 8-bit number. Used for serialization etc.
2054*/
2055static quint8 get_font_bits(int version, const QFontPrivate *f)
2056{
2057 Q_ASSERT(f != nullptr);
2058 quint8 bits = 0;
2059 if (f->request.style)
2060 bits |= 0x01;
2061 if (f->underline)
2062 bits |= 0x02;
2063 if (f->overline)
2064 bits |= 0x40;
2065 if (f->strikeOut)
2066 bits |= 0x04;
2067 if (f->request.fixedPitch)
2068 bits |= 0x08;
2069 // if (f.hintSetByUser)
2070 // bits |= 0x10;
2071 if (version >= QDataStream::Qt_4_0) {
2072 if (f->kerning)
2073 bits |= 0x10;
2074 }
2075 if (f->request.style == QFont::StyleOblique)
2076 bits |= 0x80;
2077 return bits;
2078}
2079
2080static quint8 get_extended_font_bits(const QFontPrivate *f)
2081{
2082 Q_ASSERT(f != nullptr);
2083 quint8 bits = 0;
2084 if (f->request.ignorePitch)
2085 bits |= 0x01;
2086 if (f->letterSpacingIsAbsolute)
2087 bits |= 0x02;
2088 return bits;
2089}
2090
2091/* \internal
2092 Internal function. Sets boolean font settings from an unsigned
2093 8-bit number. Used for serialization etc.
2094*/
2095static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
2096{
2097 Q_ASSERT(f != nullptr);
2098 f->request.style = (bits & 0x01) != 0 ? QFont::StyleItalic : QFont::StyleNormal;
2099 f->underline = (bits & 0x02) != 0;
2100 f->overline = (bits & 0x40) != 0;
2101 f->strikeOut = (bits & 0x04) != 0;
2102 f->request.fixedPitch = (bits & 0x08) != 0;
2103 // f->hintSetByUser = (bits & 0x10) != 0;
2104 if (version >= QDataStream::Qt_4_0)
2105 f->kerning = (bits & 0x10) != 0;
2106 if ((bits & 0x80) != 0)
2107 f->request.style = QFont::StyleOblique;
2108}
2109
2110static void set_extended_font_bits(quint8 bits, QFontPrivate *f)
2111{
2112 Q_ASSERT(f != nullptr);
2113 f->request.ignorePitch = (bits & 0x01) != 0;
2114 f->letterSpacingIsAbsolute = (bits & 0x02) != 0;
2115}
2116#endif
2117
2118/*!
2119 Returns the font's key, a textual representation of a font. It is
2120 typically used as the key for a cache or dictionary of fonts.
2121
2122 \sa QMap
2123*/
2124QString QFont::key() const
2125{
2126 return toString();
2127}
2128
2129/*!
2130 Returns a description of the font. The description is a
2131 comma-separated list of the attributes, perfectly suited for use
2132 in QSettings, and consists of the following:
2133
2134 \list
2135 \li Font family
2136 \li Point size
2137 \li Pixel size
2138 \li Style hint
2139 \li Font weight
2140 \li Font style
2141 \li Underline
2142 \li Strike out
2143 \li Fixed pitch
2144 \li Always \e{0}
2145 \li Capitalization
2146 \li Letter spacing
2147 \li Word spacing
2148 \li Stretch
2149 \li Style strategy
2150 \li Font style
2151 \li Font features
2152 \li Variable axes
2153 \endlist
2154
2155 \sa fromString()
2156 */
2157QString QFont::toString() const
2158{
2159 const QChar comma(u',');
2160 QString fontDescription = family() + comma +
2161 QString::number( pointSizeF()) + comma +
2162 QString::number( pixelSize()) + comma +
2163 QString::number((int) styleHint()) + comma +
2164 QString::number( weight()) + comma +
2165 QString::number((int) style()) + comma +
2166 QString::number((int) underline()) + comma +
2167 QString::number((int) strikeOut()) + comma +
2168 QString::number((int)fixedPitch()) + comma +
2169 QString::number((int) false) + comma +
2170 QString::number((int)capitalization()) + comma +
2171 QString::number((int)letterSpacingType()) + comma +
2172 QString::number(letterSpacing()) + comma +
2173 QString::number(wordSpacing()) + comma +
2174 QString::number(stretch()) + comma +
2175 QString::number((int)styleStrategy()) + comma +
2176 styleName();
2177
2178 fontDescription += comma + QString::number(d->features.size());
2179 for (const auto &[tag, value] : std::as_const(d->features).asKeyValueRange())
2180 fontDescription += comma + QLatin1StringView{tag.toString()} + u'=' + QString::number(value);
2181
2182 fontDescription += comma + QString::number(d->request.variableAxisValues.size());
2183 for (const auto &[tag, value] : std::as_const(d->request.variableAxisValues).asKeyValueRange())
2184 fontDescription += comma + QLatin1StringView{tag.toString()} + u'=' + QString::number(value);
2185
2186 return fontDescription;
2187}
2188
2189/*!
2190 \fn size_t qHash(const QFont &key, size_t seed)
2191 \qhashold{QFont}
2192 \since 5.3
2193*/
2194size_t qHash(const QFont &font, size_t seed) noexcept
2195{
2196 return qHash(QFontPrivate::get(font)->request, seed);
2197}
2198
2200{
2201 const int separator = view.indexOf(u'=');
2202 if (separator == -1)
2203 return std::nullopt;
2204
2205 const std::optional<QFont::Tag> tag = QFont::Tag::fromString(view.sliced(0, separator));
2206 if (!tag)
2207 return std::nullopt;
2208
2209 bool valueOk = false;
2210 const quint32 value = view.sliced(separator + 1).toUInt(&valueOk);
2211 if (!valueOk)
2212 return std::nullopt;
2213
2214 return std::make_pair(*tag, value);
2215}
2216
2217static std::optional<std::pair<QFont::Tag, float>> variableAxisFromString(QStringView view)
2218{
2219 const int separator = view.indexOf(u'=');
2220 if (separator == -1)
2221 return std::nullopt;
2222
2223 const std::optional<QFont::Tag> tag = QFont::Tag::fromString(view.sliced(0, separator));
2224 if (!tag)
2225 return std::nullopt;
2226
2227 bool valueOk = false;
2228 const float value = view.sliced(separator + 1).toFloat(&valueOk);
2229 if (!valueOk)
2230 return std::nullopt;
2231
2232 return std::make_pair(*tag, value);
2233}
2234
2235/*!
2236 Sets this font to match the description \a descrip. The description
2237 is a comma-separated list of the font attributes, as returned by
2238 toString().
2239
2240 \sa toString()
2241 */
2242bool QFont::fromString(const QString &descrip)
2243{
2244 const auto sr = QStringView(descrip).trimmed();
2245 const auto l = sr.split(u',');
2246 const int count = l.size();
2247 if (!count || (count > 2 && count < 10) || l.first().isEmpty()) {
2248 qWarning("QFont::fromString: Invalid description '%s'",
2249 descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
2250 return false;
2251 }
2252
2253 setFamily(l[0].toString());
2254 if (count > 1 && l[1].toDouble() > 0.0)
2255 setPointSizeF(l[1].toDouble());
2256
2257 if (count >= 10) {
2258 if (l[2].toInt() > 0)
2259 setPixelSize(l[2].toInt());
2260 setStyleHint((StyleHint) l[3].toInt());
2261 if (count >= 16)
2262 setWeight(QFont::Weight(l[4].toInt()));
2263 else
2264 setWeight(QFont::Weight(qt_legacyToOpenTypeWeight(l[4].toInt())));
2265 setStyle((QFont::Style)l[5].toInt());
2266 setUnderline(l[6].toInt());
2267 setStrikeOut(l[7].toInt());
2268 setFixedPitch(l[8].toInt());
2269 if (!d->request.fixedPitch) // assume 'false' fixedPitch equals default
2270 d->request.ignorePitch = true;
2271 if (count >= 16) {
2272 setCapitalization((Capitalization)l[10].toInt());
2273 setLetterSpacing((SpacingType)l[11].toInt(), l[12].toDouble());
2274 setWordSpacing(l[13].toDouble());
2275 setStretch(l[14].toInt());
2276 setStyleStrategy((StyleStrategy)l[15].toInt());
2277 }
2278
2279 if (count == 11)
2280 d->request.styleName = l[10].toString();
2281 else if (count >= 17)
2282 d->request.styleName = l[16].toString();
2283 else
2284 d->request.styleName.clear();
2285
2286 clearFeatures();
2287 clearVariableAxes();
2288
2289 int position = 17;
2290 if (position >= count)
2291 return true;
2292
2293 const int featureCount = l[position++].toInt();
2294 if (position + featureCount > count)
2295 return true;
2296
2297 for (int i = 0; i < featureCount; ++i) {
2298 if (const auto feature = fontFeatureFromString(l[position++]))
2299 setFeature(feature->first, feature->second);
2300 }
2301
2302 if (position >= count)
2303 return true;
2304
2305 const int variableAxisCount = l[position++].toInt();
2306 if (position + variableAxisCount > count)
2307 return true;
2308
2309 for (int i = 0; i < variableAxisCount; ++i) {
2310 if (const auto axis = variableAxisFromString(l[position++]))
2311 setVariableAxis(axis->first, axis->second);
2312 }
2313 }
2314
2315 return true;
2316}
2317
2318/*! \fn void QFont::initialize()
2319 \internal
2320
2321 Internal function that initializes the font system. The font cache
2322 and font dict do not alloc the keys. The key is a QString which is
2323 shared between QFontPrivate and QXFontName.
2324*/
2325void QFont::initialize()
2326{
2327}
2328
2329/*! \fn void QFont::cleanup()
2330 \internal
2331
2332 Internal function that cleans up the font system.
2333*/
2334void QFont::cleanup()
2335{
2336 QFontCache::cleanup();
2337}
2338
2339/*! \internal
2340
2341 Internal function that dumps font cache statistics.
2342*/
2343void QFont::cacheStatistics()
2344{
2345}
2346
2347/*!
2348 \class QFont::Tag
2349 \brief The QFont::Tag type provides access to advanced font features.
2350 \since 6.7
2351 \inmodule QtGui
2352
2353 QFont provides access to advanced features when shaping text. A feature is defined
2354 by a tag, which can be represented as a four-character string, or as a 32bit integer
2355 value. This type represents such a tag in a type-safe way. It can be constructed from
2356 a four-character, 8bit string literal, or from a corresponding 32bit integer value.
2357 Using a shorter or longer string literal will result in a compile-time error.
2358
2359 \code
2360 QFont font;
2361 // Correct
2362 font.setFeature("frac");
2363
2364 // Wrong - won't compile
2365 font.setFeature("fraction");
2366
2367 // Wrong - will produce runtime warning and fail
2368 font.setFeature(u"fraction"_s);
2369 \endcode
2370
2371 The named constructors allow to create a tag from an 32bit integer or string value,
2372 and will return a \c std::nullopt when the input is invalid.
2373
2374 \sa QFont::setFeature(), QFont::featureTags()
2375*/
2376
2377/*!
2378 \fn QFont::Tag::Tag()
2379
2380 Default constructor, producing an invalid tag.
2381*/
2382
2383/*!
2384 \fn template <size_t N> QFont::Tag::Tag(const char (&str)[N]) noexcept
2385
2386 Constructs a tag from a string literal, \a str. The literal must be exactly four
2387 characters long.
2388
2389 \code
2390 font.setFeature("frac", 1);
2391 \endcode
2392
2393 \sa fromString(), fromValue()
2394*/
2395
2396/*!
2397 \fn bool QFont::Tag::comparesEqual(const QFont::Tag &lhs, const QFont::Tag &rhs) noexcept
2398 \fn Qt::strong_ordering QFont::Tag::compareThreeWay(const QFont::Tag &lhs, const QFont::Tag &rhs) noexcept
2399
2400 Compare \a lhs with \a rhs for equality and ordering.
2401*/
2402
2403/*!
2404 \fn size_t QFont::Tag::qHash(QFont::Tag key, size_t seed) noexcept
2405 \qhash{QFont::Tag}
2406*/
2407
2408/*!
2409 \fn quint32 QFont::Tag::value() const noexcept
2410
2411 Returns the numerical value of this tag.
2412
2413 \sa isValid(), fromValue()
2414*/
2415
2416/*!
2417 \fn bool QFont::Tag::isValid() const noexcept
2418
2419 Returns whether the tag is valid. A tag is valid if its value is not zero.
2420
2421 \sa value(), fromValue(), fromString()
2422*/
2423
2424/*!
2425 \fn QByteArray QFont::Tag::toString() const noexcept
2426
2427 Returns the string representation of this tag as a byte array.
2428
2429 \sa fromString()
2430*/
2431
2432/*!
2433 \fn std::optional<QFont::Tag> QFont::Tag::fromValue(quint32 value) noexcept
2434
2435 Returns a tag constructed from \a value, or \c std::nullopt if the tag produced
2436 would be invalid.
2437
2438 \sa isValid()
2439*/
2440
2441/*!
2442 Returns a tag constructed from the string in \a view. The string must be exactly
2443 four characters long.
2444
2445 Returns \c std::nullopt if the input is not four characters long, or if the tag
2446 produced would be invalid.
2447
2448 \sa isValid(), fromValue()
2449*/
2450std::optional<QFont::Tag> QFont::Tag::fromString(QAnyStringView view) noexcept
2451{
2452 if (view.size() != 4) {
2453 qWarning("The tag name must be exactly 4 characters long!");
2454 return std::nullopt;
2455 }
2456 const QFont::Tag maybeTag = view.visit([](auto view) {
2457 using CharType = decltype(view.at(0));
2458 if constexpr (std::is_same_v<CharType, char>) {
2459 const char bytes[5] = { view.at(0), view.at(1), view.at(2), view.at(3), 0 };
2460 return Tag(bytes);
2461 } else {
2462 const char bytes[5] = { view.at(0).toLatin1(), view.at(1).toLatin1(),
2463 view.at(2).toLatin1(), view.at(3).toLatin1(), 0 };
2464 return Tag(bytes);
2465 }
2466 });
2467 return maybeTag.isValid() ? std::optional<Tag>(maybeTag) : std::nullopt;
2468}
2469
2470/*!
2471 \fn QDataStream &QFont::Tag::operator<<(QDataStream &, QFont::Tag)
2472 \fn QDataStream &QFont::Tag::operator>>(QDataStream &, QFont::Tag &)
2473
2474 Data stream operators for QFont::Tag.
2475*/
2476
2477/*!
2478 \since 6.7
2479
2480 Applies a \a value to the variable axis corresponding to \a tag.
2481
2482 Variable fonts provide a way to store multiple variations (with different weights, widths
2483 or styles) in the same font file. The variations are given as floating point values for
2484 a pre-defined set of parameters, called "variable axes". Specific instances are typically
2485 given names by the font designer, and, in Qt, these can be selected using setStyleName()
2486 just like traditional sub-families.
2487
2488 In some cases, it is also useful to provide arbitrary values for the different axes. For
2489 instance, if a font has a Regular and Bold sub-family, you may want a weight in-between these.
2490 You could then manually request this by supplying a custom value for the "wght" axis in the
2491 font.
2492
2493 \code
2494 QFont font;
2495 font.setVariableAxis("wght", (QFont::Normal + QFont::Bold) / 2.0f);
2496 \endcode
2497
2498 If the "wght" axis is supported by the font and the given value is within its defined range,
2499 a font corresponding to the weight 550.0 will be provided.
2500
2501 There are a few standard axes than many fonts provide, such as "wght" (weight), "wdth" (width),
2502 "ital" (italic) and "opsz" (optical size). They each have indivdual ranges defined in the font
2503 itself. For instance, "wght" may span from 100 to 900 (QFont::Thin to QFont::Black) whereas
2504 "ital" can span from 0 to 1 (from not italic to fully italic).
2505
2506 A font may also choose to define custom axes; the only limitation is that the name has to
2507 meet the requirements for a QFont::Tag (sequence of four latin-1 characters.)
2508
2509 By default, no variable axes are set.
2510
2511 \note On Windows, variable axes are not supported if the optional GDI font backend is in use.
2512
2513 \sa unsetVariableAxis
2514 */
2515void QFont::setVariableAxis(Tag tag, float value)
2516{
2517 if (tag.isValid()) {
2518 if (resolve_mask & QFont::VariableAxesResolved && d->hasVariableAxis(tag, value))
2519 return;
2520
2521 detach();
2522
2523 d->setVariableAxis(tag, value);
2524 resolve_mask |= QFont::VariableAxesResolved;
2525 }
2526}
2527
2528/*!
2529 \since 6.7
2530
2531 Unsets a previously set variable axis value given by \a tag.
2532
2533 \note If no value has previously been given for this tag, the QFont will still consider its
2534 variable axes as set when resolving against other QFont values.
2535
2536 \sa setVariableAxis
2537*/
2538void QFont::unsetVariableAxis(Tag tag)
2539{
2540 if (tag.isValid()) {
2541 detach();
2542
2543 d->unsetVariableAxis(tag);
2544 resolve_mask |= QFont::VariableAxesResolved;
2545 }
2546}
2547
2548/*!
2549 \since 6.7
2550
2551 Returns a list of tags for all variable axes currently set on this QFont.
2552
2553 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
2554
2555 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
2556*/
2557QList<QFont::Tag> QFont::variableAxisTags() const
2558{
2559 return d->request.variableAxisValues.keys();
2560}
2561
2562/*!
2563 \since 6.7
2564
2565 Returns the value set for a specific variable axis \a tag. If the tag has not been set, 0.0 will
2566 be returned instead.
2567
2568 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
2569
2570 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
2571*/
2572float QFont::variableAxisValue(Tag tag) const
2573{
2574 return d->request.variableAxisValues.value(tag);
2575}
2576
2577/*!
2578 \since 6.7
2579
2580 Returns true if a value for the variable axis given by \a tag has been set on the QFont,
2581 otherwise returns false.
2582
2583 See \l{QFont::}{setVariableAxis()} for more details on font variable axes.
2584
2585 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), variableAxisValue(), clearVariableAxes()
2586*/
2587bool QFont::isVariableAxisSet(Tag tag) const
2588{
2589 return d->request.variableAxisValues.contains(tag);
2590}
2591
2592/*!
2593 \since 6.7
2594
2595 Clears any previously set variable axis values on the QFont.
2596
2597 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
2598
2599 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), variableAxisValue()
2600*/
2601void QFont::clearVariableAxes()
2602{
2603 if (d->request.variableAxisValues.isEmpty())
2604 return;
2605
2606 detach();
2607 d->request.variableAxisValues.clear();
2608}
2609
2610
2611/*!
2612 \since 6.7
2613 \overload
2614
2615 Applies an integer value to the typographical feature specified by \a tag when shaping the
2616 text. This provides advanced access to the font shaping process, and can be used to support
2617 font features that are otherwise not covered in the API.
2618
2619 The feature is specified by a \l{QFont::Tag}{tag}, which is typically encoded from the
2620 four-character feature name in the font feature map.
2621
2622 This integer \a value passed along with the tag in most cases represents a boolean value: A zero
2623 value means the feature is disabled, and a non-zero value means it is enabled. For certain
2624 font features, however, it may have other interpretations. For example, when applied to the
2625 \c salt feature, the value is an index that specifies the stylistic alternative to use.
2626
2627 For example, the \c frac font feature will convert diagonal fractions separated with a slash
2628 (such as \c 1/2) with a different representation. Typically this will involve baking the full
2629 fraction into a single character width (such as \c ½).
2630
2631 If a font supports the \c frac feature, then it can be enabled in the shaper by setting
2632 \c{features["frac"] = 1} in the font feature map.
2633
2634 \note By default, Qt will enable and disable certain font features based on other font
2635 properties. In particular, the \c kern feature will be enabled/disabled depending on the
2636 \l kerning() property of the QFont. In addition, all ligature features
2637 (\c liga, \c clig, \c dlig, \c hlig) will be disabled if a \l letterSpacing() is applied,
2638 but only for writing systems where the use of ligature is cosmetic. For writing systems where
2639 ligatures are required, the features will remain in their default state. The values set using
2640 setFeature() and related functions will override the default behavior. If, for instance,
2641 the feature "kern" is set to 1, then kerning will always be enabled, regardless of whether the
2642 kerning property is set to false. Similarly, if it is set to 0, then it will always be disabled.
2643 To reset a font feature to its default behavior, you can unset it using unsetFeature().
2644
2645 \sa QFont::Tag, clearFeatures(), unsetFeature(), featureTags()
2646*/
2647void QFont::setFeature(Tag tag, quint32 value)
2648{
2649 if (tag.isValid()) {
2650 d->detachButKeepEngineData(this);
2651 d->setFeature(tag, value);
2652 resolve_mask |= QFont::FeaturesResolved;
2653 }
2654}
2655
2656/*!
2657 \since 6.7
2658 \overload
2659
2660 Unsets the \a tag from the map of explicitly enabled/disabled features.
2661
2662 \note Even if the feature has not previously been added, this will mark the font features map
2663 as modified in this QFont, so that it will take precedence when resolving against other fonts.
2664
2665 Unsetting an existing feature on the QFont reverts behavior to the default.
2666
2667 See \l setFeature() for more details on font features.
2668
2669 \sa QFont::Tag, clearFeatures(), setFeature(), featureTags(), featureValue()
2670*/
2671void QFont::unsetFeature(Tag tag)
2672{
2673 if (tag.isValid()) {
2674 d->detachButKeepEngineData(this);
2675 d->unsetFeature(tag);
2676 resolve_mask |= QFont::FeaturesResolved;
2677 }
2678}
2679
2680/*!
2681 \since 6.7
2682
2683 Returns a list of tags for all font features currently set on this QFont.
2684
2685 See \l{QFont::}{setFeature()} for more details on font features.
2686
2687 \sa QFont::Tag, setFeature(), unsetFeature(), isFeatureSet(), clearFeatures()
2688*/
2689QList<QFont::Tag> QFont::featureTags() const
2690{
2691 return d->features.keys();
2692}
2693
2694/*!
2695 \since 6.7
2696
2697 Returns the value set for a specific feature \a tag. If the tag has not been set, 0 will be
2698 returned instead.
2699
2700 See \l{QFont::}{setFeature()} for more details on font features.
2701
2702 \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), isFeatureSet()
2703*/
2704quint32 QFont::featureValue(Tag tag) const
2705{
2706 return d->features.value(tag);
2707}
2708
2709/*!
2710 \since 6.7
2711
2712 Returns true if a value for the feature given by \a tag has been set on the QFont, otherwise
2713 returns false.
2714
2715 See \l{QFont::}{setFeature()} for more details on font features.
2716
2717 \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), featureValue()
2718*/
2719bool QFont::isFeatureSet(Tag tag) const
2720{
2721 return d->features.contains(tag);
2722}
2723
2724/*!
2725 \since 6.7
2726
2727 Clears any previously set features on the QFont.
2728
2729 See \l{QFont::}{setFeature()} for more details on font features.
2730
2731 \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), featureValue()
2732*/
2733void QFont::clearFeatures()
2734{
2735 if (d->features.isEmpty())
2736 return;
2737
2738 d->detachButKeepEngineData(this);
2739 d->features.clear();
2740}
2741
2742extern QStringList qt_fallbacksForFamily(const QString &family,
2743 QFont::Style style,
2744 QFont::StyleHint styleHint,
2745 QFontDatabasePrivate::ExtendedScript script);
2746
2747/*!
2748 \fn QString QFont::defaultFamily() const
2749
2750 Returns the family name that corresponds to the current style
2751 hint.
2752
2753 \sa StyleHint, styleHint(), setStyleHint()
2754*/
2755QString QFont::defaultFamily() const
2756{
2757 const QStringList fallbacks = qt_fallbacksForFamily(QString(),
2758 QFont::StyleNormal,
2759 QFont::StyleHint(d->request.styleHint),
2760 QFontDatabasePrivate::Script_Common);
2761 if (!fallbacks.isEmpty())
2762 return fallbacks.first();
2763 return QString();
2764}
2765
2766/*!
2767 \since 5.13
2768
2769 Returns the requested font family names, i.e. the names set in the last
2770 setFamilies() call or via the constructor. Otherwise it returns an
2771 empty list.
2772
2773 \sa setFamily(), setFamilies(), family(), substitutes(), substitute()
2774*/
2775
2776QStringList QFont::families() const
2777{
2778 return d->request.families;
2779}
2780
2781/*!
2782 \since 5.13
2783
2784 Sets the list of family names for the font. The names are case
2785 insensitive and may include a foundry name. The first family in
2786 \a families will be set as the main family for the font.
2787
2788 Each family name entry in \a families may optionally also include a
2789 foundry name, e.g. "Helvetica [Cronyx]". If the family is
2790 available from more than one foundry and the foundry isn't
2791 specified, an arbitrary foundry is chosen. If the family isn't
2792 available a family will be set using the \l{QFont}{font matching}
2793 algorithm.
2794
2795 \sa family(), families(), setFamily(), setStyleHint(), QFontInfo
2796*/
2797
2798void QFont::setFamilies(const QStringList &families)
2799{
2800 if ((resolve_mask & QFont::FamiliesResolved) && d->request.families == families)
2801 return;
2802 detach();
2803 d->request.families = families;
2804 resolve_mask |= QFont::FamiliesResolved;
2805}
2806
2807
2808/*****************************************************************************
2809 QFont stream functions
2810 *****************************************************************************/
2811#ifndef QT_NO_DATASTREAM
2812
2813/*!
2814 \relates QFont
2815
2816 Writes the font \a font to the data stream \a s. (toString()
2817 writes to a text stream.)
2818
2819 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
2820*/
2821QDataStream &operator<<(QDataStream &s, const QFont &font)
2822{
2823 if (s.version() == 1) {
2824 s << font.d->request.families.constFirst().toLatin1();
2825 } else {
2826 s << font.d->request.families.constFirst();
2827 if (s.version() >= QDataStream::Qt_5_4)
2828 s << font.d->request.styleName;
2829 }
2830
2831 if (s.version() >= QDataStream::Qt_4_0) {
2832 // 4.0
2833 double pointSize = font.d->request.pointSize;
2834 qint32 pixelSize = font.d->request.pixelSize;
2835 s << pointSize;
2836 s << pixelSize;
2837 } else if (s.version() <= 3) {
2838 qint16 pointSize = (qint16) (font.d->request.pointSize * 10);
2839 if (pointSize < 0) {
2840 pointSize = (qint16)QFontInfo(font).pointSize() * 10;
2841 }
2842 s << pointSize;
2843 } else {
2844 s << (qint16) (font.d->request.pointSize * 10);
2845 s << (qint16) font.d->request.pixelSize;
2846 }
2847
2848 s << (quint8) font.d->request.styleHint;
2849 if (s.version() >= QDataStream::Qt_3_1) {
2850 // Continue writing 8 bits for versions < 5.4 so that we don't write too much,
2851 // even though we need 16 to store styleStrategy, so there is some data loss.
2852 if (s.version() >= QDataStream::Qt_5_4)
2853 s << (quint16) font.d->request.styleStrategy;
2854 else
2855 s << (quint8) font.d->request.styleStrategy;
2856 }
2857
2858 if (s.version() < QDataStream::Qt_6_0)
2859 s << quint8(0) << quint8(qt_openTypeToLegacyWeight(font.d->request.weight));
2860 else
2861 s << quint16(font.d->request.weight);
2862
2863 s << get_font_bits(s.version(), font.d.data());
2864 if (s.version() >= QDataStream::Qt_4_3)
2865 s << (quint16)font.d->request.stretch;
2866 if (s.version() >= QDataStream::Qt_4_4)
2867 s << get_extended_font_bits(font.d.data());
2868 if (s.version() >= QDataStream::Qt_4_5) {
2869 s << font.d->letterSpacing.value();
2870 s << font.d->wordSpacing.value();
2871 }
2872 if (s.version() >= QDataStream::Qt_5_4)
2873 s << (quint8)font.d->request.hintingPreference;
2874 if (s.version() >= QDataStream::Qt_5_6)
2875 s << (quint8)font.d->capital;
2876 if (s.version() >= QDataStream::Qt_5_13) {
2877 if (s.version() < QDataStream::Qt_6_0)
2878 s << font.d->request.families.mid(1);
2879 else
2880 s << font.d->request.families;
2881 }
2882 if (s.version() >= QDataStream::Qt_6_6)
2883 s << font.d->features;
2884 if (s.version() >= QDataStream::Qt_6_7)
2885 s << font.d->request.variableAxisValues;
2886 return s;
2887}
2888
2889
2890/*!
2891 \relates QFont
2892
2893 Reads the font \a font from the data stream \a s. (fromString()
2894 reads from a text stream.)
2895
2896 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
2897*/
2898QDataStream &operator>>(QDataStream &s, QFont &font)
2899{
2900 font.d = new QFontPrivate;
2901 font.resolve_mask = QFont::AllPropertiesResolved;
2902
2903 quint8 styleHint, bits;
2904 quint16 styleStrategy = QFont::PreferDefault;
2905
2906 if (s.version() == 1) {
2907 QByteArray fam;
2908 s >> fam;
2909 font.d->request.families = QStringList(QString::fromLatin1(fam));
2910 } else {
2911 QString fam;
2912 s >> fam;
2913 font.d->request.families = QStringList(fam);
2914 if (s.version() >= QDataStream::Qt_5_4)
2915 s >> font.d->request.styleName;
2916 }
2917
2918 if (s.version() >= QDataStream::Qt_4_0) {
2919 // 4.0
2920 double pointSize;
2921 qint32 pixelSize;
2922 s >> pointSize;
2923 s >> pixelSize;
2924 font.d->request.pointSize = qreal(pointSize);
2925 font.d->request.pixelSize = pixelSize;
2926 } else {
2927 qint16 pointSize, pixelSize = -1;
2928 s >> pointSize;
2929 if (s.version() >= 4)
2930 s >> pixelSize;
2931 font.d->request.pointSize = qreal(pointSize / 10.);
2932 font.d->request.pixelSize = pixelSize;
2933 }
2934 s >> styleHint;
2935 if (s.version() >= QDataStream::Qt_3_1) {
2936 if (s.version() >= QDataStream::Qt_5_4) {
2937 s >> styleStrategy;
2938 } else {
2939 quint8 tempStyleStrategy;
2940 s >> tempStyleStrategy;
2941 styleStrategy = tempStyleStrategy;
2942 }
2943 }
2944
2945 if (s.version() < QDataStream::Qt_6_0) {
2946 quint8 charSet;
2947 quint8 weight;
2948 s >> charSet;
2949 s >> weight;
2950 font.d->request.weight = qt_legacyToOpenTypeWeight(weight);
2951 } else {
2952 quint16 weight;
2953 s >> weight;
2954 font.d->request.weight = weight;
2955 }
2956
2957 s >> bits;
2958
2959 font.d->request.styleHint = styleHint;
2960 font.d->request.styleStrategy = styleStrategy;
2961
2962 set_font_bits(s.version(), bits, font.d.data());
2963
2964 if (s.version() >= QDataStream::Qt_4_3) {
2965 quint16 stretch;
2966 s >> stretch;
2967 font.d->request.stretch = stretch;
2968 }
2969
2970 if (s.version() >= QDataStream::Qt_4_4) {
2971 quint8 extendedBits;
2972 s >> extendedBits;
2973 set_extended_font_bits(extendedBits, font.d.data());
2974 }
2975 if (s.version() >= QDataStream::Qt_4_5) {
2976 int value;
2977 s >> value;
2978 font.d->letterSpacing.setValue(value);
2979 s >> value;
2980 font.d->wordSpacing.setValue(value);
2981 }
2982 if (s.version() >= QDataStream::Qt_5_4) {
2983 quint8 value;
2984 s >> value;
2985 font.d->request.hintingPreference = QFont::HintingPreference(value);
2986 }
2987 if (s.version() >= QDataStream::Qt_5_6) {
2988 quint8 value;
2989 s >> value;
2990 font.d->capital = QFont::Capitalization(value);
2991 }
2992 if (s.version() >= QDataStream::Qt_5_13) {
2993 QStringList value;
2994 s >> value;
2995 if (s.version() < QDataStream::Qt_6_0)
2996 font.d->request.families.append(value);
2997 else
2998 font.d->request.families = value;
2999 }
3000 if (s.version() >= QDataStream::Qt_6_6) {
3001 font.d->features.clear();
3002 s >> font.d->features;
3003 }
3004 if (s.version() >= QDataStream::Qt_6_7) {
3005 font.d->request.variableAxisValues.clear();
3006 s >> font.d->request.variableAxisValues;
3007 }
3008
3009 return s;
3010}
3011
3012QDataStream &operator<<(QDataStream &stream, QFont::Tag tag)
3013{
3014 stream << tag.value();
3015 return stream;
3016}
3017
3018QDataStream &operator>>(QDataStream &stream, QFont::Tag &tag)
3019{
3020 quint32 value;
3021 stream >> value;
3022 if (const auto maybeTag = QFont::Tag::fromValue(value))
3023 tag = *maybeTag;
3024 else
3025 stream.setStatus(QDataStream::ReadCorruptData);
3026 return stream;
3027}
3028
3029#endif // QT_NO_DATASTREAM
3030
3031
3032/*****************************************************************************
3033 QFontInfo member functions
3034 *****************************************************************************/
3035
3036/*!
3037 \class QFontInfo
3038 \reentrant
3039
3040 \brief The QFontInfo class provides general information about fonts.
3041 \inmodule QtGui
3042
3043 \ingroup appearance
3044 \ingroup shared
3045
3046 The QFontInfo class provides the same access functions as QFont,
3047 e.g. family(), pointSize(), italic(), weight(), fixedPitch(),
3048 styleHint() etc. But whilst the QFont access functions return the
3049 values that were set, a QFontInfo object returns the values that
3050 apply to the font that will actually be used to draw the text.
3051
3052 For example, when the program asks for a 25pt Courier font on a
3053 machine that has a non-scalable 24pt Courier font, QFont will
3054 (normally) use the 24pt Courier for rendering. In this case,
3055 QFont::pointSize() returns 25 and QFontInfo::pointSize() returns
3056 24.
3057
3058 There are three ways to create a QFontInfo object.
3059 \list 1
3060 \li Calling the QFontInfo constructor with a QFont creates a font
3061 info object for a screen-compatible font, i.e. the font cannot be
3062 a printer font. If the font is changed later, the font
3063 info object is \e not updated.
3064
3065 (Note: If you use a printer font the values returned may be
3066 inaccurate. Printer fonts are not always accessible so the nearest
3067 screen font is used if a printer font is supplied.)
3068
3069 \li QWidget::fontInfo() returns the font info for a widget's font.
3070 This is equivalent to calling QFontInfo(widget->font()). If the
3071 widget's font is changed later, the font info object is \e not
3072 updated.
3073
3074 \li QPainter::fontInfo() returns the font info for a painter's
3075 current font. If the painter's font is changed later, the font
3076 info object is \e not updated.
3077 \endlist
3078
3079 \section1 Checking for the existence of a font
3080
3081 Sometimes it can be useful to check if a font exists before attempting
3082 to use it. The most thorough way of doing so is by using \l {exactMatch()}:
3083
3084 \code
3085 const QFont segoeFont(QLatin1String("Segoe UI"));
3086 if (QFontInfo(segoeFont).exactMatch()) {
3087 // Use the font...
3088 }
3089 \endcode
3090
3091 However, this deep search of families can be expensive on some platforms.
3092 \c QFontDatabase::families().contains() is a faster, but less thorough
3093 alternative:
3094
3095 \code
3096 const QLatin1String segoeUiFamilyName("Segoe UI");
3097 if (QFontDatabase::families().contains(segoeUiFamilyName)) {
3098 const QFont segoeFont(segoeUiFamilyName);
3099 // Use the font...
3100 }
3101 \endcode
3102
3103 It's less thorough because it's not a complete search: some font family
3104 aliases may be missing from the list. However, this approach results in
3105 faster application startup times, and so should always be preferred if
3106 possible.
3107
3108 \sa QFont, QFontMetrics, QFontDatabase
3109*/
3110
3111/*!
3112 Constructs a font info object for \a font.
3113
3114 The font must be screen-compatible, i.e. a font you use when
3115 drawing text in \l{QWidget}{widgets} or \l{QPixmap}{pixmaps}, not QPicture or QPrinter.
3116
3117 The font info object holds the information for the font that is
3118 passed in the constructor at the time it is created, and is not
3119 updated if the font's attributes are changed later.
3120
3121 Use QPainter::fontInfo() to get the font info when painting.
3122 This will give correct results also when painting on paint device
3123 that is not screen-compatible.
3124
3125 \sa {Checking for the existence of a font}
3126*/
3127QFontInfo::QFontInfo(const QFont &font)
3128 : d(font.d)
3129{
3130}
3131
3132/*!
3133 Constructs a copy of \a fi.
3134*/
3135QFontInfo::QFontInfo(const QFontInfo &fi)
3136 : d(fi.d)
3137{
3138}
3139
3140/*!
3141 Destroys the font info object.
3142*/
3143QFontInfo::~QFontInfo()
3144{
3145}
3146
3147/*!
3148 Assigns the font info in \a fi.
3149*/
3150QFontInfo &QFontInfo::operator=(const QFontInfo &fi)
3151{
3152 d = fi.d;
3153 return *this;
3154}
3155
3156/*!
3157 \fn void QFontInfo::swap(QFontInfo &other)
3158 \since 5.0
3159 \memberswap{font info instance}
3160*/
3161
3162/*!
3163 Returns the family name of the matched window system font.
3164
3165 \sa QFont::family(), {Checking for the existence of a font}
3166*/
3167QString QFontInfo::family() const
3168{
3169 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3170 Q_ASSERT(engine != nullptr);
3171 return engine->fontDef.families.isEmpty() ? QString() : engine->fontDef.families.constFirst();
3172}
3173
3174/*!
3175 \since 4.8
3176
3177 Returns the style name of the matched window system font on
3178 systems that support it.
3179
3180 \sa QFont::styleName()
3181*/
3182QString QFontInfo::styleName() const
3183{
3184 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3185 Q_ASSERT(engine != nullptr);
3186 return engine->fontDef.styleName;
3187}
3188
3189/*!
3190 Returns the point size of the matched window system font.
3191
3192 \sa pointSizeF(), QFont::pointSize()
3193*/
3194int QFontInfo::pointSize() const
3195{
3196 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3197 Q_ASSERT(engine != nullptr);
3198 return qRound(engine->fontDef.pointSize);
3199}
3200
3201/*!
3202 Returns the point size of the matched window system font.
3203
3204 \sa QFont::pointSizeF()
3205*/
3206qreal QFontInfo::pointSizeF() const
3207{
3208 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3209 Q_ASSERT(engine != nullptr);
3210 return engine->fontDef.pointSize;
3211}
3212
3213/*!
3214 Returns the pixel size of the matched window system font.
3215
3216 \sa QFont::pointSize()
3217*/
3218int QFontInfo::pixelSize() const
3219{
3220 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3221 Q_ASSERT(engine != nullptr);
3222 return engine->fontDef.pixelSize;
3223}
3224
3225/*!
3226 Returns the italic value of the matched window system font.
3227
3228 \sa QFont::italic()
3229*/
3230bool QFontInfo::italic() const
3231{
3232 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3233 Q_ASSERT(engine != nullptr);
3234 return engine->fontDef.style != QFont::StyleNormal;
3235}
3236
3237/*!
3238 Returns the style value of the matched window system font.
3239
3240 \sa QFont::style()
3241*/
3242QFont::Style QFontInfo::style() const
3243{
3244 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3245 Q_ASSERT(engine != nullptr);
3246 return (QFont::Style)engine->fontDef.style;
3247}
3248
3249
3250#if QT_DEPRECATED_SINCE(6, 0)
3251/*!
3252 \deprecated Use weight() instead.
3253
3254 Returns the weight of the font converted to the non-standard font
3255 weight scale used in Qt 5 and earlier versions.
3256
3257 Since Qt 6, the OpenType standard's font weight scale is used instead
3258 of a non-standard scale. This requires conversion from values that
3259 use the old scale. For convenience, this function may be used when
3260 porting from code which uses the old weight scale.
3261
3262 \sa QFont::setWeight(), weight(), QFontInfo
3263*/
3264int QFontInfo::legacyWeight() const
3265{
3266 return qt_openTypeToLegacyWeight(weight());
3267}
3268#endif // QT_DEPRECATED_SINCE(6, 0)
3269
3270
3271/*!
3272 Returns the weight of the matched window system font.
3273
3274 \sa QFont::weight(), bold()
3275*/
3276int QFontInfo::weight() const
3277{
3278 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3279 Q_ASSERT(engine != nullptr);
3280 return engine->fontDef.weight;
3281
3282}
3283
3284/*!
3285 \fn bool QFontInfo::bold() const
3286
3287 Returns \c true if weight() would return a value greater than
3288 QFont::Normal; otherwise returns \c false.
3289
3290 \sa weight(), QFont::bold()
3291*/
3292
3293/*!
3294 Returns the underline value of the matched window system font.
3295
3296 \sa QFont::underline()
3297
3298 \internal
3299
3300 Here we read the underline flag directly from the QFont.
3301 This is OK for X11 and for Windows because we always get what we want.
3302*/
3303bool QFontInfo::underline() const
3304{
3305 return d->underline;
3306}
3307
3308/*!
3309 Returns the overline value of the matched window system font.
3310
3311 \sa QFont::overline()
3312
3313 \internal
3314
3315 Here we read the overline flag directly from the QFont.
3316 This is OK for X11 and for Windows because we always get what we want.
3317*/
3318bool QFontInfo::overline() const
3319{
3320 return d->overline;
3321}
3322
3323/*!
3324 Returns the strikeout value of the matched window system font.
3325
3326 \sa QFont::strikeOut()
3327
3328 \internal Here we read the strikeOut flag directly from the QFont.
3329 This is OK for X11 and for Windows because we always get what we want.
3330*/
3331bool QFontInfo::strikeOut() const
3332{
3333 return d->strikeOut;
3334}
3335
3336/*!
3337 Returns the fixed pitch value of the matched window system font.
3338
3339 \sa QFont::fixedPitch()
3340*/
3341bool QFontInfo::fixedPitch() const
3342{
3343 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3344 Q_ASSERT(engine != nullptr);
3345#ifdef Q_OS_MAC
3346 if (!engine->fontDef.fixedPitchComputed) {
3347 QChar ch[2] = { u'i', u'm' };
3348 QGlyphLayoutArray<2> g;
3349 int l = 2;
3350 if (engine->stringToCMap(ch, 2, &g, &l, {}) < 0)
3351 Q_UNREACHABLE();
3352 Q_ASSERT(l == 2);
3353 engine->fontDef.fixedPitch = g.advances[0] == g.advances[1];
3354 engine->fontDef.fixedPitchComputed = true;
3355 }
3356#endif
3357 return engine->fontDef.fixedPitch;
3358}
3359
3360/*!
3361 Returns the style of the matched window system font.
3362
3363 Currently only returns the style hint set in QFont.
3364
3365 \sa QFont::styleHint(), QFont::StyleHint
3366*/
3367QFont::StyleHint QFontInfo::styleHint() const
3368{
3369 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3370 Q_ASSERT(engine != nullptr);
3371 return (QFont::StyleHint) engine->fontDef.styleHint;
3372}
3373
3374/*!
3375 Returns \c true if the matched window system font is exactly the same
3376 as the one specified by the font; otherwise returns \c false.
3377
3378 \sa QFont::exactMatch()
3379*/
3380bool QFontInfo::exactMatch() const
3381{
3382 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3383 Q_ASSERT(engine != nullptr);
3384 return d->request.exactMatch(engine->fontDef);
3385}
3386
3387/*!
3388 \since 6.9
3389
3390 If the font is a variable font, this function will return the
3391 list of axes the font supports.
3392
3393 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
3394*/
3395QList<QFontVariableAxis> QFontInfo::variableAxes() const
3396{
3397 QFontEngine *engine = d->engineForScript(QChar::Script_Common);
3398 Q_ASSERT(engine != nullptr);
3399 return engine->variableAxes();
3400}
3401
3402
3403// **********************************************************************
3404// QFontCache
3405// **********************************************************************
3406
3407using namespace std::chrono_literals;
3408
3409#ifdef QFONTCACHE_DEBUG
3410// fast timeouts for debugging
3411static constexpr auto fast_timeout = 1s;
3412static constexpr auto slow_timeout = 5s;
3413#else
3414static constexpr auto fast_timeout = 10s;
3415static constexpr auto slow_timeout = 5min;
3416#endif // QFONTCACHE_DEBUG
3417
3418#ifndef QFONTCACHE_MIN_COST
3419# define QFONTCACHE_MIN_COST 4*1024 // 4mb
3420#endif
3421const uint QFontCache::min_cost = QFONTCACHE_MIN_COST;
3422Q_GLOBAL_STATIC(QThreadStorage<QFontCache *>, theFontCache)
3423
3424QFontCache *QFontCache::instance()
3425{
3426 QFontCache *&fontCache = theFontCache()->localData();
3427 if (!fontCache)
3428 fontCache = new QFontCache;
3429 return fontCache;
3430}
3431
3432void QFontCache::cleanup()
3433{
3434 QThreadStorage<QFontCache *> *cache = nullptr;
3435 QT_TRY {
3436 cache = theFontCache();
3437 } QT_CATCH (const std::bad_alloc &) {
3438 // no cache - just ignore
3439 }
3440 if (cache && cache->hasLocalData())
3441 cache->setLocalData(nullptr);
3442}
3443
3444Q_CONSTINIT static QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(0);
3445
3446QFontCache::QFontCache()
3447 : QObject(), total_cost(0), max_cost(min_cost),
3448 current_timestamp(0), fast(false),
3449 autoClean(QGuiApplication::instance()
3450 && (QGuiApplication::instance()->thread() == QThread::currentThread())),
3451 m_id(font_cache_id.fetchAndAddRelaxed(1) + 1)
3452{
3453}
3454
3455QFontCache::~QFontCache()
3456{
3457 clear();
3458}
3459
3460void QFontCache::clear()
3461{
3462 {
3463 EngineDataCache::Iterator it = engineDataCache.begin(),
3464 end = engineDataCache.end();
3465 while (it != end) {
3466 QFontEngineData *data = it.value();
3467 for (int i = 0; i < QFontDatabasePrivate::ScriptCount; ++i) {
3468 if (data->engines[i]) {
3469 if (!data->engines[i]->ref.deref()) {
3470 Q_ASSERT(engineCacheCount.value(data->engines[i]) == 0);
3471 delete data->engines[i];
3472 }
3473 data->engines[i] = nullptr;
3474 }
3475 }
3476 if (!data->ref.deref()) {
3477 delete data;
3478 } else {
3479 FC_DEBUG("QFontCache::clear: engineData %p still has refcount %d",
3480 data, data->ref.loadRelaxed());
3481 }
3482 ++it;
3483 }
3484 }
3485
3486 engineDataCache.clear();
3487
3488
3489 bool mightHaveEnginesLeftForCleanup;
3490 do {
3491 mightHaveEnginesLeftForCleanup = false;
3492 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
3493 it != end; ++it) {
3494 QFontEngine *engine = it.value().data;
3495 if (engine) {
3496 const int cacheCount = --engineCacheCount[engine];
3497 Q_ASSERT(cacheCount >= 0);
3498 if (!engine->ref.deref()) {
3499 Q_ASSERT(cacheCount == 0);
3500 mightHaveEnginesLeftForCleanup = engine->type() == QFontEngine::Multi;
3501 delete engine;
3502 } else if (cacheCount == 0) {
3503 FC_DEBUG("QFontCache::clear: engine %p still has refcount %d",
3504 engine, engine->ref.loadRelaxed());
3505 }
3506 it.value().data = nullptr;
3507 }
3508 }
3509 } while (mightHaveEnginesLeftForCleanup);
3510
3511 engineCache.clear();
3512 engineCacheCount.clear();
3513
3514
3515 total_cost = 0;
3516 max_cost = min_cost;
3517}
3518
3519
3520QFontEngineData *QFontCache::findEngineData(const QFontDef &def) const
3521{
3522 EngineDataCache::ConstIterator it = engineDataCache.constFind(def);
3523 if (it == engineDataCache.constEnd())
3524 return nullptr;
3525
3526 // found
3527 return it.value();
3528}
3529
3530void QFontCache::insertEngineData(const QFontDef &def, QFontEngineData *engineData)
3531{
3532#ifdef QFONTCACHE_DEBUG
3533 FC_DEBUG("QFontCache: inserting new engine data %p", engineData);
3534 if (engineDataCache.contains(def)) {
3535 FC_DEBUG(" QFontCache already contains engine data %p for key=(%g %g %d %d %d)",
3536 engineDataCache.value(def), def.pointSize,
3537 def.pixelSize, def.weight, def.style, def.fixedPitch);
3538 }
3539#endif
3540 Q_ASSERT(!engineDataCache.contains(def));
3541
3542 engineData->ref.ref();
3543 // Decrease now rather than waiting
3544 if (total_cost > min_cost * 2 && engineDataCache.size() >= QFONTCACHE_DECREASE_TRIGGER_LIMIT)
3545 decreaseCache();
3546
3547 engineDataCache.insert(def, engineData);
3548 increaseCost(sizeof(QFontEngineData));
3549}
3550
3551QFontEngine *QFontCache::findEngine(const Key &key)
3552{
3553 EngineCache::Iterator it = engineCache.find(key),
3554 end = engineCache.end();
3555 if (it == end) return nullptr;
3556
3557 Q_ASSERT(it.value().data != nullptr);
3558 Q_ASSERT(key.multi == (it.value().data->type() == QFontEngine::Multi));
3559
3560 // found... update the hitcount and timestamp
3561 updateHitCountAndTimeStamp(it.value());
3562
3563 return it.value().data;
3564}
3565
3566void QFontCache::updateHitCountAndTimeStamp(Engine &value)
3567{
3568 value.hits++;
3569 value.timestamp = ++current_timestamp;
3570
3571 FC_DEBUG("QFontCache: found font engine\n"
3572 " %p: timestamp %4u hits %3u ref %2d/%2d, type %d",
3573 value.data, value.timestamp, value.hits,
3574 value.data->ref.loadRelaxed(), engineCacheCount.value(value.data),
3575 value.data->type());
3576}
3577
3578void QFontCache::insertEngine(const Key &key, QFontEngine *engine, bool insertMulti)
3579{
3580 Q_ASSERT(engine != nullptr);
3581 Q_ASSERT(key.multi == (engine->type() == QFontEngine::Multi));
3582
3583#ifdef QFONTCACHE_DEBUG
3584 FC_DEBUG("QFontCache: inserting new engine %p, refcount %d", engine, engine->ref.loadRelaxed());
3585 if (!insertMulti && engineCache.contains(key)) {
3586 FC_DEBUG(" QFontCache already contains engine %p for key=(%g %g %d %d %d)",
3587 engineCache.value(key).data, key.def.pointSize,
3588 key.def.pixelSize, key.def.weight, key.def.style, key.def.fixedPitch);
3589 }
3590#endif
3591 engine->ref.ref();
3592 // Decrease now rather than waiting
3593 if (total_cost > min_cost * 2 && engineCache.size() >= QFONTCACHE_DECREASE_TRIGGER_LIMIT)
3594 decreaseCache();
3595
3596 Engine data(engine);
3597 data.timestamp = ++current_timestamp;
3598
3599 if (insertMulti)
3600 engineCache.insert(key, data);
3601 else
3602 engineCache.replace(key, data);
3603 // only increase the cost if this is the first time we insert the engine
3604 if (++engineCacheCount[engine] == 1)
3605 increaseCost(engine->cache_cost);
3606}
3607
3608void QFontCache::increaseCost(uint cost)
3609{
3610 cost = (cost + 512) / 1024; // store cost in kb
3611 cost = cost > 0 ? cost : 1;
3612 total_cost += cost;
3613
3614 FC_DEBUG(" COST: increased %u kb, total_cost %u kb, max_cost %u kb",
3615 cost, total_cost, max_cost);
3616
3617 if (total_cost > max_cost) {
3618 max_cost = total_cost;
3619
3620 if (!autoClean)
3621 return;
3622
3623 if (!timer.isActive() || ! fast) {
3624 FC_DEBUG(" TIMER: starting fast timer (%d s)", static_cast<int>(fast_timeout.count()));
3625
3626 timer.start(fast_timeout, this);
3627 fast = true;
3628 }
3629 }
3630}
3631
3632void QFontCache::decreaseCost(uint cost)
3633{
3634 cost = (cost + 512) / 1024; // cost is stored in kb
3635 cost = cost > 0 ? cost : 1;
3636 Q_ASSERT(cost <= total_cost);
3637 total_cost -= cost;
3638
3639 FC_DEBUG(" COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
3640 cost, total_cost, max_cost);
3641}
3642
3643void QFontCache::timerEvent(QTimerEvent *)
3644{
3645 FC_DEBUG("QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
3646 current_timestamp);
3647
3648 if (total_cost <= max_cost && max_cost <= min_cost) {
3649 FC_DEBUG(" cache redused sufficiently, stopping timer");
3650
3651 timer.stop();
3652 fast = false;
3653
3654 return;
3655 }
3656 decreaseCache();
3657}
3658
3659void QFontCache::decreaseCache()
3660{
3661 // go through the cache and count up everything in use
3662 uint in_use_cost = 0;
3663
3664 {
3665 FC_DEBUG(" SWEEP engine data:");
3666
3667 // make sure the cost of each engine data is at least 1kb
3668 const uint engine_data_cost =
3669 sizeof(QFontEngineData) > 1024 ? sizeof(QFontEngineData) : 1024;
3670
3671 EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
3672 end = engineDataCache.constEnd();
3673 for (; it != end; ++it) {
3674 FC_DEBUG(" %p: ref %2d", it.value(), int(it.value()->ref.loadRelaxed()));
3675
3676 if (it.value()->ref.loadRelaxed() != 1)
3677 in_use_cost += engine_data_cost;
3678 }
3679 }
3680
3681 {
3682 FC_DEBUG(" SWEEP engine:");
3683
3684 EngineCache::ConstIterator it = engineCache.constBegin(),
3685 end = engineCache.constEnd();
3686 for (; it != end; ++it) {
3687 const auto useCount = engineCacheCount.value(it.value().data);
3688 const auto refCount = it.value().data->ref.loadRelaxed();
3689 const auto cacheCost = it.value().data->cache_cost;
3690
3691 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
3692 it.value().data, it.value().timestamp, it.value().hits,
3693 refCount, useCount, cacheCost);
3694
3695 Q_ASSERT(useCount > 0);
3696 if (useCount > 0 && refCount > useCount)
3697 in_use_cost += cacheCost / useCount;
3698 }
3699
3700 // attempt to make up for rounding errors
3701 in_use_cost += engineCache.size();
3702 }
3703
3704 in_use_cost = (in_use_cost + 512) / 1024; // cost is stored in kb
3705
3706 /*
3707 calculate the new maximum cost for the cache
3708
3709 NOTE: in_use_cost is *not* correct due to rounding errors in the
3710 above algorithm. instead of worrying about getting the
3711 calculation correct, we are more interested in speed, and use
3712 in_use_cost as a floor for new_max_cost
3713 */
3714 uint new_max_cost = qMax(qMax(max_cost / 2, in_use_cost), min_cost);
3715
3716 FC_DEBUG(" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
3717 in_use_cost, total_cost, max_cost, new_max_cost);
3718
3719 if (autoClean) {
3720 if (new_max_cost == max_cost) {
3721 if (fast) {
3722 FC_DEBUG(" cannot shrink cache, slowing timer");
3723
3724 if (timer.isActive()) {
3725 timer.start(slow_timeout, this);
3726 fast = false;
3727 }
3728
3729 return;
3730 } else if (! fast) {
3731 FC_DEBUG(" dropping into passing gear");
3732
3733 timer.start(fast_timeout, this);
3734 fast = true; }
3735 }
3736 }
3737
3738 max_cost = new_max_cost;
3739
3740 {
3741 FC_DEBUG(" CLEAN engine data:");
3742
3743 // clean out all unused engine data
3744 EngineDataCache::Iterator it = engineDataCache.begin();
3745 while (it != engineDataCache.end()) {
3746 if (it.value()->ref.loadRelaxed() == 1) {
3747 FC_DEBUG(" %p", it.value());
3748 decreaseCost(sizeof(QFontEngineData));
3749 it.value()->ref.deref();
3750 delete it.value();
3751 it = engineDataCache.erase(it);
3752 } else {
3753 ++it;
3754 }
3755 }
3756 }
3757
3758 FC_DEBUG(" CLEAN engine:");
3759
3760 // clean out the engine cache just enough to get below our new max cost
3761 bool cost_decreased;
3762 do {
3763 cost_decreased = false;
3764
3765 EngineCache::Iterator it = engineCache.begin(),
3766 end = engineCache.end();
3767 // determine the oldest and least popular of the unused engines
3768 uint oldest = ~0u;
3769 uint least_popular = ~0u;
3770
3771 EngineCache::Iterator jt = end;
3772
3773 for ( ; it != end; ++it) {
3774 if (it.value().data->ref.loadRelaxed() != engineCacheCount.value(it.value().data))
3775 continue;
3776
3777 if (it.value().timestamp < oldest && it.value().hits <= least_popular) {
3778 oldest = it.value().timestamp;
3779 least_popular = it.value().hits;
3780 jt = it;
3781 }
3782 }
3783
3784 it = jt;
3785 if (it != end) {
3786 FC_DEBUG(" %p: timestamp %4u hits %2u ref %2d/%2d, type %d",
3787 it.value().data, it.value().timestamp, it.value().hits,
3788 it.value().data->ref.loadRelaxed(), engineCacheCount.value(it.value().data),
3789 it.value().data->type());
3790
3791 QFontEngine *fontEngine = it.value().data;
3792 // get rid of all occurrences
3793 it = engineCache.begin();
3794 while (it != engineCache.end()) {
3795 if (it.value().data == fontEngine) {
3796 fontEngine->ref.deref();
3797 it = engineCache.erase(it);
3798 } else {
3799 ++it;
3800 }
3801 }
3802 // and delete the last occurrence
3803 Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
3804 decreaseCost(fontEngine->cache_cost);
3805 delete fontEngine;
3806 engineCacheCount.remove(fontEngine);
3807
3808 cost_decreased = true;
3809 }
3810 } while (cost_decreased && total_cost > max_cost);
3811}
3812
3813
3814#ifndef QT_NO_DEBUG_STREAM
3815QDebug operator<<(QDebug stream, const QFont &font)
3816{
3817 QDebugStateSaver saver(stream);
3818 stream.nospace().noquote();
3819 stream << "QFont(";
3820
3821 if (stream.verbosity() == QDebug::DefaultVerbosity) {
3822 stream << font.toString() << ")";
3823 return stream;
3824 }
3825
3826 QString fontDescription;
3827 QDebug debug(&fontDescription);
3828 debug.nospace();
3829
3830 const QFont defaultFont(new QFontPrivate);
3831
3832 for (int property = QFont::SizeResolved; property < QFont::AllPropertiesResolved; property <<= 1) {
3833 const bool resolved = (font.resolve_mask & property) != 0;
3834 if (!resolved && stream.verbosity() == QDebug::MinimumVerbosity)
3835 continue;
3836
3837 #define QFONT_DEBUG_SKIP_DEFAULT(prop)
3838 if ((font.prop() == defaultFont.prop()) && stream.verbosity() == 1)
3839 continue;
3840
3841 QDebugStateSaver saver(debug);
3842
3843 switch (property) {
3844 case QFont::SizeResolved:
3845 if (font.pointSizeF() >= 0)
3846 debug << font.pointSizeF() << "pt";
3847 else if (font.pixelSize() >= 0)
3848 debug << font.pixelSize() << "px";
3849 else
3850 Q_UNREACHABLE();
3851 break;
3852 case QFont::StyleHintResolved:
3853 QFONT_DEBUG_SKIP_DEFAULT(styleHint);
3854 debug.verbosity(1) << font.styleHint(); break;
3855 case QFont::StyleStrategyResolved:
3856 QFONT_DEBUG_SKIP_DEFAULT(styleStrategy);
3857 debug.verbosity(1) << font.styleStrategy(); break;
3858 case QFont::WeightResolved:
3859 debug.verbosity(1) << QFont::Weight(font.weight()); break;
3860 case QFont::StyleResolved:
3862 debug.verbosity(0) << font.style(); break;
3863 case QFont::UnderlineResolved:
3864 QFONT_DEBUG_SKIP_DEFAULT(underline);
3865 debug << "underline=" << font.underline(); break;
3866 case QFont::OverlineResolved:
3867 QFONT_DEBUG_SKIP_DEFAULT(overline);
3868 debug << "overline=" << font.overline(); break;
3869 case QFont::StrikeOutResolved:
3870 QFONT_DEBUG_SKIP_DEFAULT(strikeOut);
3871 debug << "strikeOut=" << font.strikeOut(); break;
3872 case QFont::FixedPitchResolved:
3873 QFONT_DEBUG_SKIP_DEFAULT(fixedPitch);
3874 debug << "fixedPitch=" << font.fixedPitch(); break;
3875 case QFont::StretchResolved:
3876 QFONT_DEBUG_SKIP_DEFAULT(stretch);
3877 debug.verbosity(0) << QFont::Stretch(font.stretch()); break;
3878 case QFont::KerningResolved:
3879 QFONT_DEBUG_SKIP_DEFAULT(kerning);
3880 debug << "kerning=" << font.kerning(); break;
3881 case QFont::CapitalizationResolved:
3882 QFONT_DEBUG_SKIP_DEFAULT(capitalization);
3883 debug.verbosity(0) << font.capitalization(); break;
3884 case QFont::LetterSpacingResolved:
3885 QFONT_DEBUG_SKIP_DEFAULT(letterSpacing);
3886 debug << "letterSpacing=" << font.letterSpacing();
3887 debug.verbosity(0) << " (" << font.letterSpacingType() << ")";
3888 break;
3889 case QFont::HintingPreferenceResolved:
3890 QFONT_DEBUG_SKIP_DEFAULT(hintingPreference);
3891 debug.verbosity(0) << font.hintingPreference(); break;
3892 case QFont::StyleNameResolved:
3893 QFONT_DEBUG_SKIP_DEFAULT(styleName);
3894 debug << "styleName=" << font.styleName(); break;
3895 default:
3896 continue;
3897 };
3898
3899 #undef QFONT_DEBUG_SKIP_DEFAULT
3900
3901 debug << ", ";
3902 }
3903
3904 if (stream.verbosity() > QDebug::MinimumVerbosity)
3905 debug.verbosity(0) << "resolveMask=" << QFlags<QFont::ResolveProperties>(font.resolve_mask);
3906 else
3907 fontDescription.chop(2); // Last ', '
3908
3909 stream << fontDescription << ')';
3910
3911 return stream;
3912}
3913
3914QDebug operator<<(QDebug debug, QFont::Tag tag)
3915{
3916 QDebugStateSaver saver(debug);
3917 debug.noquote() << tag.toString();
3918 return debug;
3919}
3920#endif
3921
3922QT_END_NAMESPACE
3923
3924#include "moc_qfont.cpp"
\inmodule QtCore
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
Q_GUI_EXPORT int qt_openTypeToLegacyWeight(int weight)
Definition qfont.cpp:205
static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
Definition qfont.cpp:2095
QRecursiveMutex * qt_fontdatabase_mutex()
static int convertWeights(int weight, bool inverted)
Definition qfont.cpp:150
static QStringList splitIntoFamilies(const QString &family)
Definition qfont.cpp:179
#define FC_DEBUG
Definition qfont.cpp:41
Q_GUI_EXPORT int qt_legacyToOpenTypeWeight(int weight)
Definition qfont.cpp:199
static constexpr auto fast_timeout
Definition qfont.cpp:3414
static std::optional< std::pair< QFont::Tag, quint32 > > fontFeatureFromString(QStringView view)
Definition qfont.cpp:2199
QHash< QString, QStringList > QFontSubst
Definition qfont.cpp:1935
#define QFONT_DEBUG_SKIP_DEFAULT(prop)
#define QFONTCACHE_MIN_COST
Definition qfont.cpp:3419
#define QT_FONT_ENGINE_FROM_DATA(data, script)
Definition qfont.cpp:243
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:129
static constexpr auto slow_timeout
Definition qfont.cpp:3415
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:114
static quint8 get_extended_font_bits(const QFontPrivate *f)
Definition qfont.cpp:2080
Q_GUI_EXPORT int qt_defaultDpi()
Definition qfont.cpp:144
#define QFONTCACHE_DECREASE_TRIGGER_LIMIT
Definition qfont.cpp:47
QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QFontDatabasePrivate::ExtendedScript script)
static std::optional< std::pair< QFont::Tag, float > > variableAxisFromString(QStringView view)
Definition qfont.cpp:2217
static quint8 get_font_bits(int version, const QFontPrivate *f)
Definition qfont.cpp:2055
static void set_extended_font_bits(quint8 bits, QFontPrivate *f)
Definition qfont.cpp:2110
#define QFONT_WEIGHT_MIN
Definition qfont_p.h:35
#define QFONT_WEIGHT_MAX
Definition qfont_p.h:36
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
Definition qsize.h:192
uint stretch
Definition qfont_p.h:67
uint fixedPitch
Definition qfont_p.h:73
uint ignorePitch
Definition qfont_p.h:74
bool exactMatch(const QFontDef &other) const
Definition qfont.cpp:50