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