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