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