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